From a5a6e297ffade245ff5efdb71e4c551757b3575f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 28 Nov 2025 14:06:07 +0100 Subject: [PATCH] feat(nfs): Restrict server to v4 by default Can be changed with `nfs_v4_only=false` which defaults to true. Information taken from: https://wiki.debian.org/NFSServerSetup and applied directly through Ansible. Currently _irreversible_, meaning once we set the server to v4 only there is NO ansible-supported playbook to reset it to all NFSv2/3/4 versions. Has to be done manually, or could be included as manually-run playbook. --- roles/nfs/defaults/main.yaml | 3 ++ roles/nfs/tasks/main.yaml | 6 +++- roles/nfs/tasks/nfs-v4-only.yaml | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 roles/nfs/tasks/nfs-v4-only.yaml diff --git a/roles/nfs/defaults/main.yaml b/roles/nfs/defaults/main.yaml index f8088e6..8accc81 100644 --- a/roles/nfs/defaults/main.yaml +++ b/roles/nfs/defaults/main.yaml @@ -4,3 +4,6 @@ nfs_export_lines: - "/srv/media 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" - "/srv/files 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" - "/mnt/ext/data/videos 192.168.0.0/24(rw,async,no_subtree_check) 100.112.0.0/16(rw,async,no_subtree_check)" + +nfs_v4_only: true +nfs_v4_disable_rpcbind_fallback: false # needed by Debian 13 diff --git a/roles/nfs/tasks/main.yaml b/roles/nfs/tasks/main.yaml index 165ea36..478a880 100644 --- a/roles/nfs/tasks/main.yaml +++ b/roles/nfs/tasks/main.yaml @@ -10,7 +10,7 @@ ansible.builtin.template: src: exports.jinja dest: /etc/exports - mode: '0644' + mode: "0644" become: true notify: Reload nfs service @@ -22,6 +22,10 @@ become: true loop: "{{ nfs_export_lines }}" +- name: Disable NFSv2/NFSv3 to leave NFSv4-only server + ansible.builtin.include_tasks: "nfs-v4-only.yaml" + when: "nfs_v4_only" + - name: Enable nfs server unit ansible.builtin.systemd: enabled: true diff --git a/roles/nfs/tasks/nfs-v4-only.yaml b/roles/nfs/tasks/nfs-v4-only.yaml new file mode 100644 index 0000000..5c6bf00 --- /dev/null +++ b/roles/nfs/tasks/nfs-v4-only.yaml @@ -0,0 +1,48 @@ +--- +- name: Configure /etc/default/nfs-common for NFSv4-only + ansible.builtin.lineinfile: + path: /etc/default/nfs-common + regexp: '^(# *)?{{ item.key }}=.*' + line: '{{ item.key }}={{ item.val }}' + loop: + - { key: NEED_STATD, val: '"no"' } + - { key: NEED_IDMAPD, val: '"yes"' } + become: true + notify: Reload nfs service + +- name: Configure /etc/default/nfs-kernel-server for NFSv4-only + ansible.builtin.lineinfile: + path: /etc/default/nfs-kernel-server + regexp: '^(# *)?{{ item.key }}=.*' + line: '{{ item.key }}={{ item.val }}' + create: true # in case the file or the var is missing + loop: + - { key: RPCNFSDOPTS, val: '"--no-nfs-version 2 --no-nfs-version 3"' } + - { key: RPCMOUNTDOPTS, val: '"--manage-gids --no-nfs-version 2 --no-nfs-version 3"' } + become: true + notify: Reload nfs service + + # This _can_ be used on very modern kernels, but disables + # the rpcbind fallback if nfsdctl lockd configuration fails. + # Debian 13 still requires this so it is disabled by default +- name: Mask rpcbind units (not needed for NFSv4) + ansible.builtin.systemd: + name: "{{ item }}" + masked: true + state: stopped + loop: + - rpcbind.service + - rpcbind.socket + become: true + when: "nfs_v4_disable_rpcbind_fallback" + +- name: Unmask rpcbind units to keep as fallback + ansible.builtin.systemd: + name: "{{ item }}" + masked: false + state: started + loop: + - rpcbind.socket + - rpcbind.service + become: true + when: "not nfs_v4_disable_rpcbind_fallback"