diff --git a/data_safe_haven/infrastructure/programs/declarative_sre.py b/data_safe_haven/infrastructure/programs/declarative_sre.py index 483d21355b..c1525e4ed8 100644 --- a/data_safe_haven/infrastructure/programs/declarative_sre.py +++ b/data_safe_haven/infrastructure/programs/declarative_sre.py @@ -1,6 +1,7 @@ """Pulumi declarative program""" import pulumi +from pulumi import ResourceOptions from pulumi_azure_native import resources from data_safe_haven.config import Context, SREConfig @@ -384,6 +385,7 @@ def __call__(self) -> None: virtual_network=networking.virtual_network, vm_details=list(enumerate(self.config.sre.workspace_skus)), ), + opts=ResourceOptions(depends_on=[desired_state]), tags=self.tags, ) diff --git a/data_safe_haven/resources/workspace/ansible/desired_state.yaml b/data_safe_haven/resources/workspace/ansible/desired_state.yaml index e70bb1c54e..9deaf9d93d 100644 --- a/data_safe_haven/resources/workspace/ansible/desired_state.yaml +++ b/data_safe_haven/resources/workspace/ansible/desired_state.yaml @@ -6,350 +6,49 @@ - vars/pulumi_vars.yaml tasks: - - name: Update package cache - tags: apt - ansible.builtin.apt: - update_cache: true - cache_valid_time: 600 + - name: Install packages + ansible.builtin.import_tasks: tasks/packages.yaml + tags: packages - - name: List apt packages to install - tags: apt - ansible.builtin.debug: - msg: "{{ apt_packages.common | union(apt_packages[ansible_facts.distribution_release]) }}" + - name: Disable Ubuntu Pro services + ansible.builtin.import_tasks: tasks/ubuntu_pro.yaml + tags: ubuntu_pro - - name: Install apt packages - tags: apt - ansible.builtin.apt: - name: "{{ apt_packages.common | union(apt_packages[ansible_facts.distribution_release]) }}" - state: present - async: 3600 - poll: 30 - - - name: Install deb packages - tags: apt - ansible.builtin.script: - executable: /bin/bash - cmd: "/var/local/ansible/install_deb.sh {{ item.source }} {{ item.filename }} {{ item.sha256 }}" - creates: "{{ item.creates }}" - loop: "{{ deb_packages[ansible_facts.distribution_release] }}" - - - name: Install snap packages - community.general.snap: - name: "{{ item.name }}" - classic: "{{ item.classic }}" - state: present - loop: "{{ snap_packages }}" - - # https://ubuntu.com/server/docs/nvidia-drivers-installation#installing-the-drivers-on-servers-andor-for-computing-purposes - - name: Use ubuntu-drivers to install Nvidia drivers # noqa: no-handler - tags: nvidia - ansible.builtin.command: - cmd: ubuntu-drivers install --gpgpu - creates: /usr/bin/nvidia-smi - - - name: Disable and stop Ubuntu Pro services - ansible.builtin.systemd: - name: "{{ item }}" - state: stopped - enabled: false - loop: - - apt-news - - esm-cache - - - name: Enable bash autocompletion globally - ansible.builtin.blockinfile: - path: /etc/bash.bashrc - block: | - # enable bash completion in interactive shells - if [ ! $(shopt -oq posix) ]; then - if [ -f /usr/share/bash-completion/bash_completion ]; then - . /usr/share/bash-completion/bash_completion - elif [ -f /etc/bash_completion ]; then - . /etc/bash_completion - fi - fi - - - name: Copy bashrc skeleton - ansible.builtin.copy: - src: etc/skel/bashrc - dest: /etc/skel/.bashrc - mode: '0755' - - - name: Copy xsession skeleton - ansible.builtin.copy: - src: etc/skel/xsession - dest: /etc/skel/.xsession - mode: '0444' - - - name: Add ldap to /etc/nsswitch.conf - ansible.builtin.replace: - path: /etc/nsswitch.conf - regexp: '^(passwd|group|shadow)(:.*)(? /etc/audit/rules.d/50-privileged.rules - creates: /etc/audit/rules.d/50-privileged.rules - notify: Restart auditd + - name: Globally configure default user settings + ansible.builtin.import_tasks: tasks/user_config.yaml + tags: user_conf - - name: Copy ClamAV daemon configuration - ansible.builtin.copy: - src: etc/clamav/clamd.conf - dest: /etc/clamav/clamd.conf - mode: '0444' - owner: clamav - group: adm - register: clamd + - name: Configure LDAP + ansible.builtin.import_tasks: tasks/ldap.yaml + tags: ldap - - name: Enable and start ClamAV daemon - ansible.builtin.systemd: - name: clamav-daemon - enabled: true - state: started - - - name: Restart ClamAV daemon # noqa: no-handler - ansible.builtin.systemd: - name: clamav-daemon - state: restarted - when: clamd.changed - - - name: Set freshclam private mirror - ansible.builtin.lineinfile: - path: /etc/clamav/freshclam.conf - line: "PrivateMirror {{ clamav_mirror_hostname }}" - state: present - - # This is required to fetch definitions for the clamav daemon to run - - name: Initial freshclam run # noqa: command-instead-of-module - ansible.builtin.shell: - cmd: | - systemctl stop clamav-freshclam && freshclam && systemctl start clamav-freshclam - creates: '/var/lib/clamav/main.{c[vl]d,inc}' - - - name: Copy ClamAV services directory - ansible.builtin.copy: - src: etc/systemd/system/ - dest: /etc/systemd/system/ - mode: '0644' - notify: Systemd daemon reload - - - name: Enable and start freshclam - ansible.builtin.systemd: - name: clamav-freshclam - state: started - enabled: true - - - name: Enable and start ClamAV on access scan - ansible.builtin.systemd: - name: clamav-clamonacc - enabled: true - state: started - - - name: Enable and start ClamAV timer - ansible.builtin.systemd: - name: clamav-clamdscan.timer - enabled: true - state: started + - name: Configure Xrdp + ansible.builtin.import_tasks: tasks/xrdp.yaml + tags: xrdp - - name: Template pip and CRAN global configuration - ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - mode: '0444' - loop: - - src: etc/pip.conf.j2 - dest: /etc/pip.conf - - src: etc/R/Rprofile.site.j2 - dest: /etc/R/Rprofile.site + - name: Configure Xfce + ansible.builtin.import_tasks: tasks/xfce.yaml + tags: xfce - - name: Copy smoke test files directory - ansible.builtin.copy: - src: usr/local/smoke_tests/ - dest: /usr/local/smoke_tests/ - mode: '0755' + - name: Configure package proxies + ansible.builtin.import_tasks: tasks/package_proxy.yaml + tags: package_proxies - - name: Write database credential for smoke tests - ansible.builtin.template: - src: etc/database_credential.j2 - dest: /etc/database_credential - mode: '0400' + - name: Provision smoke tests + ansible.builtin.import_tasks: tasks/smoke_tests.yaml + tags: smoke_tests handlers: - name: Restart auditd diff --git a/data_safe_haven/resources/workspace/ansible/tasks/auditd.yaml b/data_safe_haven/resources/workspace/ansible/tasks/auditd.yaml new file mode 100644 index 0000000000..212c63aa1e --- /dev/null +++ b/data_safe_haven/resources/workspace/ansible/tasks/auditd.yaml @@ -0,0 +1,32 @@ +--- + +- name: Enable and start auditd service + ansible.builtin.systemd: + name: auditd + enabled: true + state: started + +- name: Get minimum uid # noqa: inline-env-var + ansible.builtin.command: + cmd: awk '/^\s*UID_MIN/{print $2}' /etc/login.defs + register: uid_min + changed_when: false + +- name: Template auditd rules + ansible.builtin.template: + src: etc/audit/rules.d/audit.rules.j2 + dest: /etc/audit/rules.d/audit.rules + mode: '0640' + notify: Restart auditd + +- name: Copy auditd privileged executable rules script + ansible.builtin.copy: + src: usr/local/bin/privileged-rules + dest: /usr/local/bin/privileged-rules + mode: '0500' + +- name: Generate auditd privileged executable rules + ansible.builtin.shell: + cmd: /usr/local/bin/privileged-rules > /etc/audit/rules.d/50-privileged.rules + creates: /etc/audit/rules.d/50-privileged.rules + notify: Restart auditd diff --git a/data_safe_haven/resources/workspace/ansible/tasks/clamav.yaml b/data_safe_haven/resources/workspace/ansible/tasks/clamav.yaml new file mode 100644 index 0000000000..4bb887f571 --- /dev/null +++ b/data_safe_haven/resources/workspace/ansible/tasks/clamav.yaml @@ -0,0 +1,62 @@ +--- + +- name: Copy ClamAV daemon configuration + ansible.builtin.copy: + src: etc/clamav/clamd.conf + dest: /etc/clamav/clamd.conf + mode: '0444' + owner: clamav + group: adm + register: clamd + +- name: Enable and start ClamAV daemon + ansible.builtin.systemd: + name: clamav-daemon + enabled: true + state: started + +- name: Restart ClamAV daemon # noqa: no-handler + ansible.builtin.systemd: + name: clamav-daemon + state: restarted + when: clamd.changed + +- name: Set freshclam private mirror + ansible.builtin.lineinfile: + path: /etc/clamav/freshclam.conf + line: "PrivateMirror {{ clamav_mirror_hostname }}" + state: present + +# This is required to fetch definitions for the clamav daemon to run +- name: Initial freshclam run # noqa: command-instead-of-module + ansible.builtin.shell: + cmd: | + systemctl stop clamav-freshclam && freshclam && systemctl start clamav-freshclam + creates: '/var/lib/clamav/main.{c[vl]d,inc}' + +- name: Copy ClamAV services + ansible.builtin.copy: + src: "{{ item }}" + dest: /etc/systemd/system/ + mode: '0644' + with_fileglob: + - "etc/systemd/system/clamav-*" + notify: Systemd daemon reload + +- name: Enable and start freshclam + ansible.builtin.systemd: + name: clamav-freshclam + state: started + enabled: true + +- name: Enable and start ClamAV on access scan + ansible.builtin.systemd: + name: clamav-clamonacc + enabled: true + state: started + +- name: Enable and start ClamAV timer + ansible.builtin.systemd: + name: clamav-clamdscan.timer + enabled: true + state: started diff --git a/data_safe_haven/resources/workspace/ansible/tasks/ldap.yaml b/data_safe_haven/resources/workspace/ansible/tasks/ldap.yaml new file mode 100644 index 0000000000..7698b1fd2b --- /dev/null +++ b/data_safe_haven/resources/workspace/ansible/tasks/ldap.yaml @@ -0,0 +1,34 @@ +--- + +- name: Add ldap to /etc/nsswitch.conf + ansible.builtin.replace: + path: /etc/nsswitch.conf + regexp: '^(passwd|group|shadow)(:.*)(?=== Waiting for Pulumi vars file... ===<" + - while (! test -f /var/local/ansible/vars/pulumi_vars.yaml) do sleep 5; done - echo ">=== Running initial desired state configuration... ===<" - systemctl start desired-state