From e5e384dcfc86119cc4acd955c513a7f98d03e040 Mon Sep 17 00:00:00 2001 From: Ryan Anderson Date: Fri, 12 Jan 2024 13:01:55 -0500 Subject: [PATCH] Process the config option `DeploymentSettings/DefaultUserHome and move the cluster user out of /home when the default_user_home option is set to local Refactored the cookbook to use an attribute for the default user's home directory so that it can be changed when using the new config option. Also simplified the users attribute file since the exta OS specific files were not adding any value and duplicating code. --- CHANGELOG.md | 1 + .../kitchen.environment-config.yml | 36 +++++++++++++ .../recipes/init.rb | 3 ++ .../recipes/init/config_default_user_home.rb | 48 +++++++++++++++++ .../recipes/config_default_user_home_spec.rb | 42 +++++++++++++++ .../controls/config_default_user_home_spec.rb | 29 ++++++++++ .../recipes/config/cluster_user.rb | 53 +++++++++++++++---- .../attributes/users.rb | 3 ++ .../attributes/users_amazon2.rb | 2 + .../attributes/users_centos7.rb | 2 + .../attributes/users_redhat8.rb | 2 + .../attributes/users_rocky8.rb | 2 + .../attributes/users_ubuntu.rb | 2 + kitchen.validate-config.yml | 1 + 14 files changed, 217 insertions(+), 9 deletions(-) create mode 100644 cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb create mode 100644 cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb create mode 100644 cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 45c1db4131..1682d248b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This file is used to list changes made in each version of the AWS ParallelCluste ------ **ENHANCEMENTS** +- Add the configuration parameter `DeploymentSettings/DefaultUserHome` to allow users to move the default user's home directory to `/local/home` instead of `/home` (default). - Add support for installing Intel OneAPI Base Toolkit and HPC Toolkit, and Intel Python. - Intel OneAPI Base Toolkits: 2023.2.0 - Intel OneAPI HPC Toolkits: 2023.2.0 diff --git a/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml b/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml index d9cdd098dd..9e6f5eb351 100644 --- a/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml +++ b/cookbooks/aws-parallelcluster-environment/kitchen.environment-config.yml @@ -752,3 +752,39 @@ suites: dependencies: - recipe:aws-parallelcluster-platform::directories - resource:spack:setup + - name: default_user_local_home_head_node + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'HeadNode' + scheduler: 'slurm' + default_user_home: 'local' + - name: default_user_local_home_compute + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'ComputeFleet' + scheduler: 'slurm' + default_user_home: 'local' + - name: default_user_local_home_login + run_list: + - recipe[aws-parallelcluster-tests::setup] + - recipe[aws-parallelcluster-environment::config_default_user_home] + verifier: + controls: + - local_default_user_home + attributes: + cluster: + node_type: 'LoginNode' + scheduler: 'slurm' + default_user_home: 'local' diff --git a/cookbooks/aws-parallelcluster-environment/recipes/init.rb b/cookbooks/aws-parallelcluster-environment/recipes/init.rb index 820f12e3df..225ce76fc2 100644 --- a/cookbooks/aws-parallelcluster-environment/recipes/init.rb +++ b/cookbooks/aws-parallelcluster-environment/recipes/init.rb @@ -17,6 +17,9 @@ action :configure end +# move the default user dir out of /home if the config param is set to 'local' +include_recipe "aws-parallelcluster-environment::config_default_user_home" + case node['cluster']['shared_storage_type'] when 'efs' include_recipe "aws-parallelcluster-environment::mount_internal_use_efs" diff --git a/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb b/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb new file mode 100644 index 0000000000..200a96c70c --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/recipes/init/config_default_user_home.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# +# Copyright:: 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the +# License. A copy of the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and +# limitations under the License. + +return if node['cluster']['default_user_home'] == 'shared' + +# Backup the cluster user's default home directory +bash "Backup #{node['cluster']['cluster_user_home']}" do + user 'root' + group 'root' + code <<-EOH + set -e + if [ -d /tmp#{node['cluster']['cluster_user_home']} ]; then + echo "/tmp#{node['cluster']['cluster_user_home']} exists!" + exit 1 + else + mkdir -p /tmp#{node['cluster']['cluster_user_home']} + fi + rsync -a #{node['cluster']['cluster_user_home']}/ /tmp#{node['cluster']['cluster_user_home']} + EOH +end + +# move the cluster user's default home directory +bash "Move #{node['cluster']['cluster_user_home']}" do + user 'root' + group 'root' + code <<-EOH + set -e + mkdir -p #{node['cluster']['cluster_user_local_home']} + rsync -a /tmp#{node['cluster']['cluster_user_home']}/ #{node['cluster']['cluster_user_local_home']} + usermod -d #{node['cluster']['cluster_user_local_home']} #{node['cluster']['cluster_user']} + chown -R #{node['cluster']['cluster_user']}: #{node['cluster']['cluster_user_local_home']} + rm -rf /tmp#{node['cluster']['cluster_user_home']} + rm -rf #{node['cluster']['cluster_user_home']} + EOH +end + +node.override['cluster']['cluster_user_home'] = node['cluster']['cluster_user_local_home'] diff --git a/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb b/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb new file mode 100644 index 0000000000..da2623c3f6 --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/spec/unit/recipes/config_default_user_home_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe 'aws-parallelcluster-environment::config_default_user_home' do + for_all_oses do |platform, version| + context "on #{platform}#{version}" do + context 'when local' do + cached(:chef_run) do + runner = runner(platform: platform, version: version) do |node| + node.override['cluster']['default_user_home'] = "local" + node.override['cluster']['cluster_user_home'] = "/home/user" + node.override['cluster']['cluster_user_local_home'] = "/local/home/user" + end + runner.converge(described_recipe) + end + cached(:node) { chef_run.node } + + it 'runs the recipe' do + is_expected.to run_bash("Backup /home/user") + is_expected.to run_bash("Move /home/user") + expect(chef_run.node['cluster']['cluster_user_home']).to eq('/local/home/user') + end + end + context 'when shared' do + cached(:chef_run) do + runner = runner(platform: platform, version: version) do |node| + node.override['cluster']['default_user_home'] = "shared" + node.override['cluster']['cluster_user_home'] = "/home/user" + node.override['cluster']['cluster_user_local_home'] = "/local/home/user" + end + runner.converge(described_recipe) + end + cached(:node) { chef_run.node } + + it 'skips the recipe' do + is_expected.not_to run_bash("Backup /home/user") + is_expected.not_to run_bash("Move /home/user") + expect(chef_run.node['cluster']['cluster_user_home']).to eq('/home/user') + end + end + end + end +end diff --git a/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb b/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb new file mode 100644 index 0000000000..c33836d37a --- /dev/null +++ b/cookbooks/aws-parallelcluster-environment/test/controls/config_default_user_home_spec.rb @@ -0,0 +1,29 @@ +# Copyright:: 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. A copy of the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "LICENSE.txt" file accompanying this file. +# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. +# See the License for the specific language governing permissions and limitations under the License. + +control 'local_default_user_home' do + title 'Check if the home directory is in a local directory' + + only_if { !os_properties.on_docker? } + + describe directory("/local/home") do + it { should exist } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('mode') { should cmp '0755' } + end + describe directory("#{node['cluster']['cluster_user_local_home']}") do + it { should exist } + its('owner') { should eq "#{node['cluster']['cluster_user']}" } + its('group') { should eq "#{node['cluster']['cluster_user']}" } + its('mode') { should cmp '0700' } + end +end diff --git a/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb b/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb index 42043323cf..58e21c855d 100644 --- a/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb +++ b/cookbooks/aws-parallelcluster-platform/recipes/config/cluster_user.rb @@ -12,53 +12,88 @@ # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and # limitations under the License. +node.override['cluster']['cluster_user_home'] = node['cluster']['cluster_user_local_home'] if node['cluster']['default_user_home'] == 'local' + case node['cluster']['node_type'] when 'HeadNode' # Setup cluster user user node['cluster']['cluster_user'] do manage_home true comment 'AWS ParallelCluster user' - home "/home/#{node['cluster']['cluster_user']}" + home "#{node['cluster']['cluster_user_home']}" shell '/bin/bash' end # Setup SSH auth for cluster user bash "ssh-keygen" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-KEYGEN set -e su - #{node['cluster']['cluster_user']} -c \"ssh-keygen -q -t ed25519 -f ~/.ssh/id_ed25519 -N ''\" KEYGEN - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/id_ed25519") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/id_ed25519") } end bash "copy_and_perms" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-PERMS set -e su - #{node['cluster']['cluster_user']} -c \"cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys && touch ~/.ssh/authorized_keys_cluster\" PERMS - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/authorized_keys_cluster") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/authorized_keys_cluster") } + end + + bash "share_auth_keys_for_local_default_user_home" do + code <<-PERMS + set -e + cp -p #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys #{node['cluster']['shared_dir']} + cp -p #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys #{node['cluster']['shared_dir_login_nodes']} + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } end bash "ssh-keyscan" do - cwd "/home/#{node['cluster']['cluster_user']}" + cwd "#{node['cluster']['cluster_user_home']}" code <<-KEYSCAN set -e su - #{node['cluster']['cluster_user']} -c \"ssh-keyscan #{node['hostname']} > ~/.ssh/known_hosts && chmod 0600 ~/.ssh/known_hosts\" KEYSCAN - not_if { ::File.exist?("/home/#{node['cluster']['cluster_user']}/.ssh/known_hosts") } + not_if { ::File.exist?("#{node['cluster']['cluster_user_home']}/.ssh/known_hosts") } + end + +when 'ComputeFleet' + # Setup cluster user + user node['cluster']['cluster_user'] do + manage_home false + comment 'AWS ParallelCluster user' + home "#{node['cluster']['cluster_user_home']}" + shell '/bin/bash' end -when 'ComputeFleet', 'LoginNode' + bash "copy_auth_file" do + code <<-PERMS + set -e + cp -p #{node['cluster']['shared_dir']}/authorized_keys #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } + end +when 'LoginNode' # Setup cluster user user node['cluster']['cluster_user'] do manage_home false comment 'AWS ParallelCluster user' - home "/home/#{node['cluster']['cluster_user']}" + home "#{node['cluster']['cluster_user_home']}" shell '/bin/bash' end + + bash "copy_auth_file" do + code <<-PERMS + set -e + cp -p #{node['cluster']['shared_dir_login_nodes']}/authorized_keys #{node['cluster']['cluster_user_home']}/.ssh/authorized_keys + PERMS + only_if { node['cluster']['default_user_home'] == 'local' } + end else raise "node_type must be HeadNode, LoginNode or ComputeFleet" end diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users.rb b/cookbooks/aws-parallelcluster-shared/attributes/users.rb index 79f0c7a48a..aec18b5aa4 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users.rb @@ -18,3 +18,6 @@ default['cluster']['munge']['user_id'] = node['cluster']['reserved_base_uid'] + 2 default['cluster']['munge']['group'] = node['cluster']['munge']['user'] default['cluster']['munge']['group_id'] = node['cluster']['munge']['user_id'] + +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb index c3e2344c89..4e329a2153 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_amazon2.rb @@ -1,3 +1,5 @@ return unless platform?('amazon') && node['platform_version'] == "2" default['cluster']['cluster_user'] = 'ec2-user' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb index d3e9442567..1577b16509 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_centos7.rb @@ -1,3 +1,5 @@ return unless platform?('centos') && node['platform_version'].to_i == 7 default['cluster']['cluster_user'] = 'centos' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb index e74551dbde..bdd4fc475e 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_redhat8.rb @@ -1,3 +1,5 @@ return unless platform?('redhat') && node['platform_version'].to_i == 8 default['cluster']['cluster_user'] = 'ec2-user' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb index 7d5dbbb588..5f4369b2ee 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_rocky8.rb @@ -1,3 +1,5 @@ return unless platform?('rocky') && node['platform_version'].to_i == 8 default['cluster']['cluster_user'] = 'rocky' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb b/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb index 9ae757f762..690381ed10 100644 --- a/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb +++ b/cookbooks/aws-parallelcluster-shared/attributes/users_ubuntu.rb @@ -1,3 +1,5 @@ return unless platform?('ubuntu') default['cluster']['cluster_user'] = 'ubuntu' +default['cluster']['cluster_user_home'] = "/home/#{node['cluster']['cluster_user']}" +default['cluster']['cluster_user_local_home'] = "/local#{node['cluster']['cluster_user_home']}" diff --git a/kitchen.validate-config.yml b/kitchen.validate-config.yml index 4e13ae3873..4fe9458392 100644 --- a/kitchen.validate-config.yml +++ b/kitchen.validate-config.yml @@ -27,6 +27,7 @@ _common_cluster_attributes: &_common_cluster_attributes nvidia: enabled: <%= ENV['NVIDIA_ENABLED'] %> shared_storage_type: ebs + default_user_home: shared _head_node_cluster_attributes: &_head_node_cluster_attributes << : *_common_cluster_attributes