aboutsummaryrefslogtreecommitdiffstats
path: root/roles/nfs_server
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:23:43 -0500
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:52:13 -0500
commit0261e875679f1bf63c8d689da7fc7e014597885d (patch)
tree3f19cd74a0c1070944f75437f30b098d6ef2ffcb /roles/nfs_server
downloadselfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.tar.gz
selfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.zip
initial commit
Diffstat (limited to 'roles/nfs_server')
-rw-r--r--roles/nfs_server/defaults/main.yml14
-rw-r--r--roles/nfs_server/files/etc/samba/local.conf14
-rw-r--r--roles/nfs_server/handlers/main.yml19
-rw-r--r--roles/nfs_server/meta/main.yml3
-rw-r--r--roles/nfs_server/tasks/autofs.yml57
-rw-r--r--roles/nfs_server/tasks/exports.yml55
-rw-r--r--roles/nfs_server/tasks/homedirs.yml112
-rw-r--r--roles/nfs_server/tasks/main.yml19
-rw-r--r--roles/nfs_server/tasks/nfs.yml41
-rw-r--r--roles/nfs_server/tasks/smb.yml54
-rw-r--r--roles/nfs_server/templates/etc/exports.j220
-rw-r--r--roles/nfs_server/templates/etc/nfs.conf.j210
-rw-r--r--roles/nfs_server/templates/etc/samba/shares.conf.j219
-rw-r--r--roles/nfs_server/vars/main.yml9
14 files changed, 446 insertions, 0 deletions
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