From 0261e875679f1bf63c8d689da7fc7e014597885d Mon Sep 17 00:00:00 2001 From: Stonewall Jackson Date: Sat, 4 Feb 2023 01:23:43 -0500 Subject: initial commit --- roles/nfs_server/defaults/main.yml | 14 +++ roles/nfs_server/files/etc/samba/local.conf | 14 +++ roles/nfs_server/handlers/main.yml | 19 ++++ roles/nfs_server/meta/main.yml | 3 + roles/nfs_server/tasks/autofs.yml | 57 +++++++++++ roles/nfs_server/tasks/exports.yml | 55 ++++++++++ roles/nfs_server/tasks/homedirs.yml | 112 +++++++++++++++++++++ roles/nfs_server/tasks/main.yml | 19 ++++ roles/nfs_server/tasks/nfs.yml | 41 ++++++++ roles/nfs_server/tasks/smb.yml | 54 ++++++++++ roles/nfs_server/templates/etc/exports.j2 | 20 ++++ roles/nfs_server/templates/etc/nfs.conf.j2 | 10 ++ .../nfs_server/templates/etc/samba/shares.conf.j2 | 19 ++++ roles/nfs_server/vars/main.yml | 9 ++ 14 files changed, 446 insertions(+) create mode 100644 roles/nfs_server/defaults/main.yml create mode 100644 roles/nfs_server/files/etc/samba/local.conf create mode 100644 roles/nfs_server/handlers/main.yml create mode 100644 roles/nfs_server/meta/main.yml create mode 100644 roles/nfs_server/tasks/autofs.yml create mode 100644 roles/nfs_server/tasks/exports.yml create mode 100644 roles/nfs_server/tasks/homedirs.yml create mode 100644 roles/nfs_server/tasks/main.yml create mode 100644 roles/nfs_server/tasks/nfs.yml create mode 100644 roles/nfs_server/tasks/smb.yml create mode 100644 roles/nfs_server/templates/etc/exports.j2 create mode 100644 roles/nfs_server/templates/etc/nfs.conf.j2 create mode 100644 roles/nfs_server/templates/etc/samba/shares.conf.j2 create mode 100644 roles/nfs_server/vars/main.yml (limited to 'roles/nfs_server') diff --git a/roles/nfs_server/defaults/main.yml b/roles/nfs_server/defaults/main.yml new file mode 100644 index 0000000..bc60543 --- /dev/null +++ b/roles/nfs_server/defaults/main.yml @@ -0,0 +1,14 @@ +nfs_mountd_port: 20048 + +nfs_exports: [] +smb_shares: [] +nfs_homedirs: [] + +nfs_homedir_user_dataset: tank/user +nfs_homedir_group_dataset: tank/group + +nfs_homedir_priv_quota: 50G +nfs_homedir_pub_quota: 10G + +nfs_homedir_options: rw +nfs_homedir_clients: [] diff --git a/roles/nfs_server/files/etc/samba/local.conf b/roles/nfs_server/files/etc/samba/local.conf new file mode 100644 index 0000000..d9f5f53 --- /dev/null +++ b/roles/nfs_server/files/etc/samba/local.conf @@ -0,0 +1,14 @@ +[global] + smb encrypt = desired + use sendfile = yes + map archive = no + name resolve order = host + mdns name = mdns + disable netbios = yes + kernel oplocks = yes + read only = no + directory mask = 0775 + create mask = 0774 + logging = syslog@2 + +include = /etc/samba/shares.conf diff --git a/roles/nfs_server/handlers/main.yml b/roles/nfs_server/handlers/main.yml new file mode 100644 index 0000000..77d3fa3 --- /dev/null +++ b/roles/nfs_server/handlers/main.yml @@ -0,0 +1,19 @@ +- name: restart nfs-server + systemd: + name: nfs-server + state: restarted + +- name: reload nfs-server + systemd: + name: nfs-server + state: reloaded + +- name: restart samba + systemd: + name: smb + state: restarted + +- name: reload samba + systemd: + name: smb + state: reloaded diff --git a/roles/nfs_server/meta/main.yml b/roles/nfs_server/meta/main.yml new file mode 100644 index 0000000..b750790 --- /dev/null +++ b/roles/nfs_server/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - role: zfs + tags: zfs diff --git a/roles/nfs_server/tasks/autofs.yml b/roles/nfs_server/tasks/autofs.yml new file mode 100644 index 0000000..57bb862 --- /dev/null +++ b/roles/nfs_server/tasks/autofs.yml @@ -0,0 +1,57 @@ +- name: create automount maps for exports + ipaautomountmap: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + name: '{{ item }}' + location: default + state: present + loop: "{{ nfs_exports | selectattr('automount_map', 'defined') | map(attribute='automount_map') | unique }}" + +- name: create automount keys for exports + ipaautomountkey: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + location: default + mapname: '{{ item.automount_map }}' + key: '{{ item.automount_key | default(zfs_mountpoints[item.dataset] | basename) }}' + info: '-fstype=nfs4 {{ ansible_fqdn }}:{{ zfs_mountpoints[item.dataset] }}' + state: present + loop: "{{ nfs_exports | selectattr('automount_map', 'defined') }}" + loop_control: + label: '{{ item.dataset }}' + +- name: create automount maps for homedirs + ipaautomountmap: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + name: '{{ item }}' + location: default + state: present + loop: + - '{{ nfs_homedir_home_automount_map }}' + - '{{ nfs_homedir_user_automount_map }}' + - '{{ nfs_homedir_group_automount_map }}' + +- name: create automount keys for homedirs + ipaautomountkey: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + location: default + mapname: '{{ nfs_homedir_group_automount_map if item.group is defined else nfs_homedir_user_automount_map }}' + key: '{{ item.group if item.group is defined else item.user }}' + info: >- + /priv -fstype=nfs4 {{ ansible_fqdn }}:{{ zfs_mountpoints[nfs_homedir_group_dataset if item.group is defined else nfs_homedir_user_dataset] }}/{{ item.group if item.group is defined else item.user }}/priv + /pub -fstype=nfs4 {{ ansible_fqdn }}:{{ zfs_mountpoints[nfs_homedir_group_dataset if item.group is defined else nfs_homedir_user_dataset] }}/{{ item.group if item.group is defined else item.user }}/pub + state: present + loop: '{{ nfs_homedirs }}' + +- name: create /home automount keys + ipaautomountkey: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + location: default + mapname: '{{ nfs_homedir_home_automount_map }}' + key: '{{ item }}' + info: '-fstype=nfs4 {{ ansible_fqdn }}:{{ zfs_mountpoints[nfs_homedir_user_dataset] }}/{{ item }}/priv' + state: present + loop: "{{ nfs_homedirs | selectattr('user', 'defined') | map(attribute='user') }}" diff --git a/roles/nfs_server/tasks/exports.yml b/roles/nfs_server/tasks/exports.yml new file mode 100644 index 0000000..10ff894 --- /dev/null +++ b/roles/nfs_server/tasks/exports.yml @@ -0,0 +1,55 @@ +- name: create zfs datasets for exports + zfs: + name: '{{ item.dataset }}' + state: present + extra_zfs_properties: '{{ item.zfs_properties if item.zfs_properties is defined else omit }}' + loop: "{{ nfs_exports | selectattr('dataset', 'defined') }}" + loop_control: + label: '{{ item.dataset }}' + +- name: collect zfs mountpoints + shell: "zfs list -Hp -o name,mountpoint | sed 's/\t/: /'" + changed_when: False + register: zfs_list_mountpoints + +- name: set zfs_mountpoints fact + set_fact: + zfs_mountpoints: '{{ zfs_list_mountpoints.stdout | from_yaml }}' + +- name: set directory permissions for exports + file: + path: '{{ zfs_mountpoints[item.dataset] }}' + owner: '{{ item.owner | default(omit) }}' + group: '{{ item.group | default(omit) }}' + mode: "{{ '0%0o' % item.mode if item.mode is defined else omit }}" + setype: _default + state: directory + loop: '{{ nfs_exports }}' + loop_control: + label: '{{ item.dataset }}' + +- name: set directory ACLs for exports + acl: + path: '{{ zfs_mountpoints[item.0.dataset] }}' + default: '{{ item.1.default | default(omit) }}' + entity: '{{ item.1.entity }}' + etype: '{{ item.1.etype }}' + permissions: '{{ item.1.permissions }}' + recalculate_mask: mask + state: present + loop: "{{ nfs_exports | selectattr('acl', 'defined') | subelements('acl') }}" + loop_control: + label: '{{ item.0.dataset }}: {{ item.1 }}' + +- name: for exports with a "default" ACL, ensure the ACL is set on the directory itself + acl: + path: '{{ zfs_mountpoints[item.0.dataset] }}' + default: no + entity: '{{ item.1.entity }}' + etype: '{{ item.1.etype }}' + permissions: '{{ item.1.permissions }}' + recalculate_mask: mask + state: present + loop: "{{ nfs_exports | selectattr('acl', 'defined') | subelements('acl') | selectattr('1.default', 'defined') | selectattr('1.default', 'equalto', True) }}" + loop_control: + label: '{{ item.0.dataset }}: {{ item.1 }}' diff --git a/roles/nfs_server/tasks/homedirs.yml b/roles/nfs_server/tasks/homedirs.yml new file mode 100644 index 0000000..0241a6e --- /dev/null +++ b/roles/nfs_server/tasks/homedirs.yml @@ -0,0 +1,112 @@ +- name: create parent zfs datasets for home directories + zfs: + name: '{{ item }}' + state: present + loop: + - '{{ nfs_homedir_user_dataset }}' + - '{{ nfs_homedir_group_dataset }}' + +- name: collect zfs mountpoints + shell: "zfs list -Hp -o name,mountpoint | sed 's/\t/: /'" + changed_when: false + register: zfs_list_mountpoints + +- name: set zfs_mountpoints fact + set_fact: + zfs_mountpoints: '{{ zfs_list_mountpoints.stdout | from_yaml }}' + +- name: set selinux context for home directories + sefcontext: + target: '{{ item }}' + setype: samba_share_t + state: present + loop: + - '{{ zfs_mountpoints[nfs_homedir_group_dataset] }}(/.*)?' + - '{{ zfs_mountpoints[nfs_homedir_user_dataset] }}(/.*)?' + register: nfs_homedir_sefcontext + +- name: apply selinux context to home directories + command: 'restorecon -R {{ zfs_mountpoints[nfs_homedir_group_dataset] }} {{ zfs_mountpoints[nfs_homedir_user_dataset] }}' + when: nfs_homedir_sefcontext.changed + +- name: check which home directories already exist + stat: + path: '{{ zfs_mountpoints[nfs_homedir_group_dataset if item.group is defined else nfs_homedir_user_dataset] }}/{{ item.group if item.group is defined else item.user }}/priv' + loop: '{{ nfs_homedirs }}' + register: nfs_homedir_stat + +- name: create zfs datasets for public home directories + zfs: + name: '{{ nfs_homedir_group_dataset if item.group is defined else nfs_homedir_user_dataset }}/{{ item.group if item.group is defined else item.user }}/pub' + state: present + extra_zfs_properties: + refquota: '{{ item.pub_quota | default(nfs_homedir_pub_quota) }}' + loop: '{{ nfs_homedirs }}' + loop_control: + label: '{{ item }}' + +- name: create zfs datasets for private home directories + zfs: + name: '{{ nfs_homedir_group_dataset if item.group is defined else nfs_homedir_user_dataset }}/{{ item.group if item.group is defined else item.user }}/priv' + state: present + extra_zfs_properties: + refquota: '{{ item.priv_quota | default(nfs_homedir_priv_quota) }}' + loop: '{{ nfs_homedirs }}' + loop_control: + label: '{{ item }}' + +- name: copy skel files into any newly-created home directories + copy: + src: /etc/skel/ + dest: '{{ zfs_mountpoints[nfs_homedir_user_dataset] }}/{{ item.user }}/priv' + remote_src: yes + owner: '{{ item.user }}' + group: '{{ item.user }}' + mode: preserve + when: + - item.user is defined + - not nfs_homedir_stat.results[index].stat.exists + loop: '{{ nfs_homedirs }}' + loop_control: + index_var: index + +- name: set directory permissions for user home directories + file: + path: "{{ zfs_mountpoints[nfs_homedir_user_dataset] }}/{{ item.0 }}/{{ item.1.name }}" + state: directory + owner: '{{ item.0 }}' + group: '{{ item.0 }}' + mode: '{{ item.1.mode }}' + setype: _default + loop: "{{ nfs_homedirs | selectattr('user', 'defined') | map(attribute='user') | product(subdirs) }}" + vars: + subdirs: + - { name: pub, mode: '755' } + - { name: priv, mode: '700' } + +- name: set directory permissions for group directories + file: + path: "{{ zfs_mountpoints[nfs_homedir_group_dataset] }}/{{ item.0 }}/{{ item.1.name }}" + state: directory + owner: root + group: '{{ item.0 }}' + mode: '{{ item.1.mode }}' + setype: _default + loop: "{{ nfs_homedirs | selectattr('group', 'defined') | map(attribute='group') | product(subdirs) }}" + vars: + subdirs: + - { name: pub, mode: '02775' } + - { name: priv, mode: '02770' } + +- name: set directory ACLs for group directories + acl: + path: '{{ zfs_mountpoints[nfs_homedir_group_dataset] }}/{{ item.0 }}/{{ item.1 }}' + default: yes + entity: '{{ item.0 }}' + etype: group + permissions: rwX + recalculate_mask: mask + state: present + loop: "{{ nfs_homedirs | selectattr('group', 'defined') | map(attribute='group') | product(['pub', 'priv']) }}" + loop_control: + label: '{{ item.0 }}: {{ item.1 }}' diff --git a/roles/nfs_server/tasks/main.yml b/roles/nfs_server/tasks/main.yml new file mode 100644 index 0000000..56e7099 --- /dev/null +++ b/roles/nfs_server/tasks/main.yml @@ -0,0 +1,19 @@ +- name: install packages + dnf: + name: '{{ nfs_packages }}' + state: present + +- name: create zfs filesystems for exports + import_tasks: exports.yml + +- name: create zfs filesystems for home directories + import_tasks: homedirs.yml + +- name: configure nfs shares + import_tasks: nfs.yml + +- name: configure smb shares + import_tasks: smb.yml + +- name: generate autofs maps + import_tasks: autofs.yml diff --git a/roles/nfs_server/tasks/nfs.yml b/roles/nfs_server/tasks/nfs.yml new file mode 100644 index 0000000..b32e48f --- /dev/null +++ b/roles/nfs_server/tasks/nfs.yml @@ -0,0 +1,41 @@ +- name: create nfs service + ipaservice: + ipaadmin_principal: '{{ ipa_user }}' + ipaadmin_password: '{{ ipa_pass }}' + name: 'nfs/{{ ansible_fqdn }}' + state: present + +- name: retrieve nfs service keytab + include_role: + name: freeipa_keytab + vars: + keytab_principal: 'nfs/{{ ansible_fqdn }}' + +- name: generate nfs.conf + template: + src: etc/nfs.conf.j2 + dest: /etc/nfs.conf + notify: restart nfs-server + +- name: generate export list + template: + src: etc/exports.j2 + dest: /etc/exports + notify: reload nfs-server + +- name: start nfs server + systemd: + name: nfs-server + state: started + enabled: yes + +- name: open firewall ports + firewalld: + service: '{{ item }}' + permanent: yes + immediate: yes + state: enabled + loop: + - nfs + - rpc-bind + - mountd diff --git a/roles/nfs_server/tasks/smb.yml b/roles/nfs_server/tasks/smb.yml new file mode 100644 index 0000000..ee050d0 --- /dev/null +++ b/roles/nfs_server/tasks/smb.yml @@ -0,0 +1,54 @@ +- name: configure samba domain member + command: + cmd: ipa-client-samba --no-homes --unattended + creates: /etc/samba/samba.keytab + +- name: add include statement to smb.conf + lineinfile: + path: /etc/samba/smb.conf + line: include = /etc/samba/local.conf + insertafter: EOF + notify: restart samba + +- name: copy samba configuration + copy: + src: etc/samba/local.conf + dest: /etc/samba/local.conf + notify: restart samba + +- name: create samba shares + template: + src: etc/samba/shares.conf.j2 + dest: /etc/samba/shares.conf + notify: reload samba + +- name: set selinux context for samba shares + sefcontext: + target: '{{ zfs_mountpoints[item.dataset] if item.dataset is defined else item.path }}(/.*)?' + setype: samba_share_t + state: present + loop: "{{ (nfs_exports | selectattr('smb_share', 'defined')) + smb_shares }}" + register: nfs_export_sefcontext + +- name: apply selinux context to samba shares + command: 'restorecon -R {{ zfs_mountpoints[item.dataset] if item.dataset is defined else item.path }}' + when: nfs_export_sefcontext.results[index].changed + loop: "{{ (nfs_exports | selectattr('smb_share', 'defined')) + smb_shares }}" + loop_control: + index_var: index + +- name: start samba services + systemd: + name: '{{ item }}' + enabled: yes + state: started + loop: + - smb + - winbind + +- name: open firewall ports + firewalld: + service: samba + permanent: yes + immediate: yes + state: enabled diff --git a/roles/nfs_server/templates/etc/exports.j2 b/roles/nfs_server/templates/etc/exports.j2 new file mode 100644 index 0000000..7f62ef5 --- /dev/null +++ b/roles/nfs_server/templates/etc/exports.j2 @@ -0,0 +1,20 @@ +{% for export in nfs_exports %} +{{ zfs_mountpoints[export.dataset] if export.dataset is defined else export.path }} {% if (export.options | default([])) %}-{% if export.options is string %}{{ export.options }}{% else %}{{ export.options | join(',') }}{% endif %}{%endif %} {% for client in export.clients %}{% if client is string %}{{ client }} {% else %}{{ client.client }}{% if (client.options | default([])) %}({% if client.options is string %}{{ client.options }}{% else %}{{ client.options | join(',') }}{% endif %}){% endif %}{% endif %} {% endfor %} + +{% endfor %} + +# user exports +{% for export in nfs_homedirs | selectattr('user', 'defined') %} +{% for subdir in ['pub', 'priv'] %} +{{ zfs_mountpoints[nfs_homedir_user_dataset] }}/{{ export.user }}/{{ subdir }} {% if (nfs_homedir_options | default([])) %}-{% if nfs_homedir_options is string %}{{ nfs_homedir_options }}{% else %}{{ nfs_homedir_options | join(',') }}{% endif %}{%endif %} {% for client in nfs_homedir_clients %}{% if client is string %}{{ client }} {% else %}{{ client.client }}{% if (client.options | default([])) %}({% if client.options is string %}{{ client.options }}{% else %}{{ client.options | join(',') }}{% endif %}){% endif %}{% endif %} {% endfor %} + +{% endfor %} +{% endfor %} + +# group exports +{% for export in nfs_homedirs | selectattr('group', 'defined') %} +{% for subdir in ['pub', 'priv'] %} +{{ zfs_mountpoints[nfs_homedir_group_dataset] }}/{{ export.group }}/{{ subdir }} {% if (nfs_homedir_options | default([])) %}-{% if nfs_homedir_options is string %}{{ nfs_homedir_options }}{% else %}{{ nfs_homedir_options | join(',') }}{% endif %}{%endif %} {% for client in nfs_homedir_clients %}{% if client is string %}{{ client }} {% else %}{{ client.client }}{% if (client.options | default([])) %}({% if client.options is string %}{{ client.options }}{% else %}{{ client.options | join(',') }}{% endif %}){% endif %}{% endif %} {% endfor %} + +{% endfor %} +{% endfor %} diff --git a/roles/nfs_server/templates/etc/nfs.conf.j2 b/roles/nfs_server/templates/etc/nfs.conf.j2 new file mode 100644 index 0000000..295f20d --- /dev/null +++ b/roles/nfs_server/templates/etc/nfs.conf.j2 @@ -0,0 +1,10 @@ +[gssd] +use-gss-proxy=1 + +[mountd] +port={{ nfs_mountd_port }} + +[nfsd] +vers2=n +vers3=y +vers4.0=n diff --git a/roles/nfs_server/templates/etc/samba/shares.conf.j2 b/roles/nfs_server/templates/etc/samba/shares.conf.j2 new file mode 100644 index 0000000..bb223ed --- /dev/null +++ b/roles/nfs_server/templates/etc/samba/shares.conf.j2 @@ -0,0 +1,19 @@ +{% for export in nfs_exports | selectattr('smb_share', 'defined') %} +[{{ export.smb_share }}] +path = {{ zfs_mountpoints[export.dataset] if export.dataset is defined else export.path }} +{% endfor %} + +{% for share in smb_shares %} +[{{ share.name }}] +path = {{ share.path }} +{% endfor %} + +{% if nfs_homedirs | selectattr('user', 'defined') %} +[users] +path = {{ zfs_mountpoints[nfs_homedir_user_dataset] }} +{% endif %} + +{% if nfs_homedirs | selectattr('group', 'defined') %} +[groups] +path = {{ zfs_mountpoints[nfs_homedir_group_dataset] }} +{% endif %} diff --git a/roles/nfs_server/vars/main.yml b/roles/nfs_server/vars/main.yml new file mode 100644 index 0000000..4c5ef2f --- /dev/null +++ b/roles/nfs_server/vars/main.yml @@ -0,0 +1,9 @@ +nfs_packages: + - nfs-utils + - nfs4-acl-tools + - ipa-client-samba + - rsync + +nfs_homedir_home_automount_map: auto.home +nfs_homedir_user_automount_map: auto.nfs_user +nfs_homedir_group_automount_map: auto.nfs_group -- cgit