From 879f62775c134f1be11af2a2fd78b9866d1267f3 Mon Sep 17 00:00:00 2001 From: Steve Brasier <33413598+sjpb@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:21:26 +0000 Subject: [PATCH] Prevent nfs being mounted by tunnelling/forwarding through login node (#595) * prevent nfs tunnelling through login node * bump nfs role * disable ssh forwarding by default --- ansible/roles/sshd/README.md | 1 + ansible/roles/sshd/defaults/main.yml | 1 + ansible/roles/sshd/templates/sshd.conf.j2 | 1 + docs/networks.md | 9 +++++++++ .../.stackhpc/inventory/group_vars/all/nfs.yml | 17 +++++++++++++++++ .../common/inventory/group_vars/all/nfs.yml | 8 +++----- requirements.yml | 2 +- 7 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 environments/.stackhpc/inventory/group_vars/all/nfs.yml diff --git a/ansible/roles/sshd/README.md b/ansible/roles/sshd/README.md index 0fac1d189..f7467a68f 100644 --- a/ansible/roles/sshd/README.md +++ b/ansible/roles/sshd/README.md @@ -5,5 +5,6 @@ Configure sshd. ## Role variables - `sshd_password_authentication`: Optional bool. Whether to enable password login. Default `false`. +- `sshd_disable_forwarding`: Optional bool. Whether to disable all forwarding features (X11, ssh-agent, TCP and StreamLocal). Default `true`. - `sshd_conf_src`: Optional string. Path to sshd configuration template. Default is in-role template. - `sshd_conf_dest`: Optional string. Path to destination for sshd configuration file. Default is `/etc/ssh/sshd_config.d/10-ansible.conf` which overides `50-{cloud-init,redhat}` files, if present. diff --git a/ansible/roles/sshd/defaults/main.yml b/ansible/roles/sshd/defaults/main.yml index 672305799..c7a83b875 100644 --- a/ansible/roles/sshd/defaults/main.yml +++ b/ansible/roles/sshd/defaults/main.yml @@ -1,3 +1,4 @@ sshd_password_authentication: false +sshd_disable_forwarding: true sshd_conf_src: sshd.conf.j2 sshd_conf_dest: /etc/ssh/sshd_config.d/10-ansible.conf diff --git a/ansible/roles/sshd/templates/sshd.conf.j2 b/ansible/roles/sshd/templates/sshd.conf.j2 index 2746f0642..862e2638e 100644 --- a/ansible/roles/sshd/templates/sshd.conf.j2 +++ b/ansible/roles/sshd/templates/sshd.conf.j2 @@ -1,2 +1,3 @@ # {{ ansible_managed }} PasswordAuthentication {{ 'yes' if sshd_password_authentication | bool else 'no' }} +DisableForwarding {{ 'yes' if sshd_disable_forwarding | bool else 'no' }} diff --git a/docs/networks.md b/docs/networks.md index 09e3bc5a6..4556ac623 100644 --- a/docs/networks.md +++ b/docs/networks.md @@ -14,6 +14,15 @@ as an SSH proxy to access the other nodes, this can create problems in recoverin the cluster if the login node is unavailable and can make Ansible problems harder to debug. +> [!WARNING] +> If home directories are on a shared filesystem with no authentication (such +> as the default NFS share) then the network(s) the fileserver is attached to +> form a security boundary. If an untrusted user can access these networks they +> could mount the home directories setting any desired uid/gid. +> +> Ensure there is no external access to these networks and that no untrusted +> instances are attached to them. + This page describes supported configurations and how to implement them using the OpenTofu variables. These will normally be set in `environments/site/tofu/terraform.tfvars` for the site base environment. If they diff --git a/environments/.stackhpc/inventory/group_vars/all/nfs.yml b/environments/.stackhpc/inventory/group_vars/all/nfs.yml new file mode 100644 index 000000000..af3861ee9 --- /dev/null +++ b/environments/.stackhpc/inventory/group_vars/all/nfs.yml @@ -0,0 +1,17 @@ +nfs_configurations: + - comment: Export /exports/home from Slurm control node as /home + nfs_enable: + server: "{{ inventory_hostname in groups['control'] }}" + # Don't mount share on server where it is exported from... + # Could do something like `nfs_clients: "{{ 'nfs_servers' not in group_names }}"` instead. + clients: "{{ inventory_hostname in groups['cluster'] and inventory_hostname not in groups['control'] }}" + nfs_server: "{{ nfs_server_default }}" + nfs_export: "/exports/home" # assumes skeleton TF is being used + nfs_client_mnt_point: "/home" + + # EXPERIMENTAL - not generally secure + - comment: Export /exports/cluster from Slurm control node + nfs_enable: + server: "{{ inventory_hostname in groups['control'] }}" + clients: false + nfs_export: "/exports/cluster" diff --git a/environments/common/inventory/group_vars/all/nfs.yml b/environments/common/inventory/group_vars/all/nfs.yml index 45b7c6967..f277170b6 100644 --- a/environments/common/inventory/group_vars/all/nfs.yml +++ b/environments/common/inventory/group_vars/all/nfs.yml @@ -16,8 +16,6 @@ nfs_configurations: nfs_export: "/exports/home" # assumes skeleton TF is being used nfs_client_mnt_point: "/home" - - comment: Export /exports/cluster from Slurm control node - nfs_enable: - server: "{{ inventory_hostname in groups['control'] }}" - clients: false - nfs_export: "/exports/cluster" +# Set 'secure' to prevent tunneling nfs mounts +# Cannot set 'root_squash' due to home directory creation +nfs_export_options: 'rw,secure,no_root_squash' diff --git a/requirements.yml b/requirements.yml index 34a436453..06da8ca7c 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,7 +1,7 @@ --- roles: - src: stackhpc.nfs - version: v23.12.1 # Tolerate state nfs file handles + version: v25.2.1 - src: https://github.com/stackhpc/ansible-role-openhpc.git version: v0.27.0 name: stackhpc.openhpc