From 1f060541c33d94f7b5b7da1fbec87daf775ebd94 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Sat, 28 Sep 2024 21:27:24 +0200 Subject: [PATCH] Refactor playbook_microk8s.yml and ansible-apply.yaml Simplify playbook_microk8s.yml by removing duplicate lines and whitespace changes. Update ansible-apply.yaml to include a scheduled job for Terraform Apply. --- .github/workflows/ansible-apply.yaml | 2 +- .github/workflows/terraform-iac-apply.yaml | 2 + .github/workflows/terraform-iac-validate.yaml | 2 +- .../workflows/terraform-k8apps-validate.yaml | 2 +- ansible/playbook_encryption.yml | 186 ++++++++++-------- ansible/playbook_microk8s.yml | 4 +- ansible/roles/microk8s/tasks/iac.yml | 6 +- .../microk8s/tasks/microk8s/encryption.yml | 0 .../roles/microk8s/tasks/setupenv/main.yml | 10 +- .../roles/microk8s/templates/microk8s.yml.j2 | 12 ++ resources/iac_user,yaml | 141 ------------- terraform/iac/buckets.tf | 2 +- 12 files changed, 136 insertions(+), 233 deletions(-) create mode 100644 ansible/roles/microk8s/tasks/microk8s/encryption.yml create mode 100644 ansible/roles/microk8s/templates/microk8s.yml.j2 delete mode 100644 resources/iac_user,yaml diff --git a/.github/workflows/ansible-apply.yaml b/.github/workflows/ansible-apply.yaml index 066c28c..568112d 100644 --- a/.github/workflows/ansible-apply.yaml +++ b/.github/workflows/ansible-apply.yaml @@ -80,8 +80,8 @@ jobs: SSH_AUTH_SOCK: /tmp/ssh_agent.sock run: | cd ansible - sectool exec ansible-playbook -u $ANSIBLE_USER playbook_encryption.yml sectool exec ansible-playbook -u $ANSIBLE_USER playbook_hardening.yml --skip-tags roles::cis::suid + sectool exec ansible-playbook -u $ANSIBLE_USER playbook_encryption.yml sectool exec ansible-playbook -u $ANSIBLE_USER playbook_microk8s.yml sectool exec ansible-playbook -u $ANSIBLE_USER playbook_gitea.yml sectool exec ansible-playbook -u $ANSIBLE_USER playbook_nextcloud.yml diff --git a/.github/workflows/terraform-iac-apply.yaml b/.github/workflows/terraform-iac-apply.yaml index 5626332..c02c8c5 100644 --- a/.github/workflows/terraform-iac-apply.yaml +++ b/.github/workflows/terraform-iac-apply.yaml @@ -1,6 +1,8 @@ name: Terraform Apply on: + schedule: + - cron: "0 1 * * 0" push: branches: - main diff --git a/.github/workflows/terraform-iac-validate.yaml b/.github/workflows/terraform-iac-validate.yaml index b48139a..8cfe460 100644 --- a/.github/workflows/terraform-iac-validate.yaml +++ b/.github/workflows/terraform-iac-validate.yaml @@ -27,7 +27,7 @@ jobs: - name: Setup Sectool uses: a13labs/setup-sectool@v1 - - name: Terraform Init + - name: Terraform Init and Validate env: VAULT_MASTER_PASSWORD: ${{ secrets.VAULT_MASTER_PASSWORD }} run: | diff --git a/.github/workflows/terraform-k8apps-validate.yaml b/.github/workflows/terraform-k8apps-validate.yaml index 3018882..55f1493 100644 --- a/.github/workflows/terraform-k8apps-validate.yaml +++ b/.github/workflows/terraform-k8apps-validate.yaml @@ -82,7 +82,7 @@ jobs: mkdir -p ~/.kube ansible -i ansible/inventory/hosts -u $ANSIBLE_USER -m fetch -a "src=/home/$ANSIBLE_USER/.kube/config dest=~/.kube/config flat=yes" microk8s - - name: Terraform Init + - name: Terraform Init and Validate env: VAULT_MASTER_PASSWORD: ${{ secrets.VAULT_MASTER_PASSWORD }} run: | diff --git a/ansible/playbook_encryption.yml b/ansible/playbook_encryption.yml index b646585..1203c45 100644 --- a/ansible/playbook_encryption.yml +++ b/ansible/playbook_encryption.yml @@ -1,118 +1,148 @@ --- -- name: Create LUKS encrypted file system with key file fetched from HTTP server +- name: Setup encrypted volume for a13labs hosts: contabo - become: yes + become: true vars: disk_image_path: /a13labs.img disk_image_size: 1G - luks_device_name: luks_device + luks_device_name: a13labs mount_point: /a13labs - key_file_path: /root/luks_keyfile + key_file_path: /root/a13labs.key key_file_url: https://a13labs-infra-{{ lookup('env','BUCKET_SUFFIX') }}.s3.fr-par.scw.cloud - key_fetch_service: fetch-a13labs-key.service + key_fetch_service: a13labs-key.service tasks: - name: Install cryptsetup and curl - apt: + ansible.builtin.apt: name: - cryptsetup - curl state: present when: ansible_os_family == 'Debian' + - name: Get mac address + ansible.builtin.shell: | + set -o pipefail + ip link show eth0 | awk '/ether/ {print $2}' + args: + executable: /bin/bash + register: mac_address + changed_when: false + + - name: Sanitize mac address + ansible.builtin.set_fact: + mac_address_sanitized: "{{ mac_address.stdout | regex_replace('[:]', '_') }}" + changed_when: false + - name: Create disk image ansible.builtin.command: fallocate -l {{ disk_image_size }} {{ disk_image_path }} args: creates: "{{ disk_image_path }}" register: disk_image - - name: Create encrypted volume + - name: Create bucket URL + ansible.builtin.set_fact: + key_file_url: "{{ key_file_url }}/keys/{{ mac_address_sanitized }}.key" + changed_when: false + + - name: Create encrypted volume # noqa no-handler when: disk_image is changed - block: - - name: Get mac address - ansible.builtin.shell: | - set -o pipefail - ip link show eth0 | awk '/ether/ {print $2}' - args: - executable: /bin/bash - register: mac_address - changed_when: false + block: - - name: Sanitize mac address - set_fact: - mac_address_sanitized: "{{ mac_address.stdout | regex_replace('[:]', '%3A') }}" - changed_when: false + - name: Download key file from Key server + ansible.builtin.uri: + url: "{{ key_file_url }}" + dest: "{{ key_file_path }}" + mode: '0600' + args: + creates: "{{ key_file_path }}" - - name: Create bucket URL - set_fact: - key_file_url: "{{ key_file_url }}/keys/{{ mac_address_sanitized }}.key" - changed_when: false + - name: Set up LUKS encryption with key file + ansible.builtin.command: cryptsetup -q luksFormat {{ disk_image_path }} {{ key_file_path }} + changed_when: false - - name: Download key file from HTTP server - ansible.builtin.uri: - url: "{{ key_file_url }}" - dest: "{{ key_file_path }}" - mode: '0600' - args: - creates: "{{ key_file_path }}" + - name: Open LUKS device with key file + ansible.builtin.command: cryptsetup luksOpen {{ disk_image_path }} {{ luks_device_name }} -d {{ key_file_path }} + register: luks_device + changed_when: false - - name: Set up LUKS encryption with key file - ansible.builtin.command: cryptsetup -q luksFormat {{ disk_image_path }} {{ key_file_path }} + - name: Create file system + ansible.builtin.command: mkfs.ext4 /dev/mapper/{{ luks_device_name }} + changed_when: false - - name: Open LUKS device with key file - ansible.builtin.command: cryptsetup luksOpen {{ disk_image_path }} {{ luks_device_name }} -d {{ key_file_path }} - register: luks_device + - name: Close LUKS device + ansible.builtin.command: cryptsetup close {{ luks_device_name }} + changed_when: false - - name: Delete key file - ansible.builtin.file: - path: "{{ key_file_path }}" - state: absent + - name: Delete key file + ansible.builtin.file: + path: "{{ key_file_path }}" + state: absent - - name: Create file system - ansible.builtin.command: mkfs.ext4 /dev/mapper/{{ luks_device_name }} + - name: Create mount point + ansible.builtin.file: + path: "{{ mount_point }}" + state: directory + mode: "0750" - - name: Create mount point - file: - path: "{{ mount_point }}" - state: directory + - name: Create systemd service to fetch key file and open LUKS device + ansible.builtin.copy: + dest: /etc/systemd/system/{{ key_fetch_service }} + mode: '0644' + content: | + [Unit] + Description=Open LUKS device + After=network-online.target - - name: Mount the file system - ansible.builtin.command: mount /dev/mapper/{{ luks_device_name }} {{ mount_point }} + [Service] + Type=oneshot + RemainAfterExit=true + ExecStartPre=/usr/bin/curl -o {{ key_file_path }} "{{ key_file_url }}" + ExecStart=/usr/sbin/cryptsetup luksOpen {{ disk_image_path }} {{ luks_device_name }} -d {{ key_file_path }} + ExecStartPost=/bin/rm -f {{ key_file_path }} + ExecStop=/usr/sbin/cryptsetup close {{ luks_device_name }} - - name: Ensure the file system is mounted - mount: - path: "{{ mount_point }}" - src: /dev/mapper/{{ luks_device_name }} - fstype: ext4 - state: mounted + [Install] + WantedBy=remote-fs.target - - name: Create systemd service to fetch key file and open LUKS device - copy: - dest: /etc/systemd/system/{{ key_fetch_service }} - content: | - [Unit] - Description=Fetch LUKS key file from HTTP server and open LUKS device - After=network-online.target - Before=cryptsetup.target + - name: Create systemd service to mount the file system + ansible.builtin.copy: + dest: /etc/systemd/system/{{ mount_point | basename }}.mount + mode: '0644' + content: | + [Unit] + Description=Mount LUKS device + After=remote-fs.target - [Service] - Type=oneshot - ExecStartPre=/usr/bin/curl -o {{ key_file_path }} {{ key_file_url }} - ExecStart=/usr/bin/cryptsetup luksOpen {{ disk_image_path }} {{ luks_device_name }} -d {{ key_file_path }} - ExecStartPost=/bin/rm -f {{ key_file_path }} + [Mount] + What=/dev/mapper/{{ luks_device_name }} + Where={{ mount_point }} + Type=ext4 + Options=defaults - [Install] - WantedBy=multi-user.target + [Install] + WantedBy=multi-user.target - - name: Reload systemd daemon - ansible.builtin.command: systemctl daemon-reload + - name: Reload systemd daemon + ansible.builtin.systemd: + daemon_reload: true - - name: Enable the key fetch service - ansible.builtin.command: systemctl enable {{ key_fetch_service }} + - name: Enable the key fetch service + ansible.builtin.systemd: + name: "{{ key_fetch_service }}" + enabled: true - - name: Add entry to /etc/fstab - lineinfile: - path: /etc/fstab - line: "/dev/mapper/{{ luks_device_name }} {{ mount_point }} ext4 defaults 0 2" - create: yes + - name: Enable the mount device + ansible.builtin.systemd: + name: "{{ mount_point | basename }}.mount" + enabled: true + - name: Start the key fetch service + ansible.builtin.systemd: + name: "{{ key_fetch_service }}" + state: started + + - name: Start the mount device + ansible.builtin.systemd: + name: "{{ mount_point | basename }}.mount" + state: started diff --git a/ansible/playbook_microk8s.yml b/ansible/playbook_microk8s.yml index 19beff6..7640605 100644 --- a/ansible/playbook_microk8s.yml +++ b/ansible/playbook_microk8s.yml @@ -1,6 +1,6 @@ --- -- name: Microk8s Setup - hosts: microk8s +- name: Microk8s Setup + hosts: microk8s gather_facts: true roles: diff --git a/ansible/roles/microk8s/tasks/iac.yml b/ansible/roles/microk8s/tasks/iac.yml index c9c5448..d6af39f 100644 --- a/ansible/roles/microk8s/tasks/iac.yml +++ b/ansible/roles/microk8s/tasks/iac.yml @@ -124,7 +124,7 @@ - k8s::iac - name: Get new config SHA1 - set_fact: + ansible.builtin.set_fact: patched_kubeconfig_sha1: "{{ patched_kubeconfig_yaml | to_nice_yaml | sha1 }}" tags: - k8s::iac @@ -136,6 +136,6 @@ dest: "{{ k8s_kubeconfig }}" owner: "{{ k8s_iac_user }}" mode: "0600" - when: kubeconfig_exists.stat.exists == false or patched_kubeconfig_sha1 != kubeconfig_exists.stat.checksum + when: not kubeconfig_exists.stat.exists or patched_kubeconfig_sha1 != kubeconfig_exists.stat.checksum tags: - - k8s::iac \ No newline at end of file + - k8s::iac diff --git a/ansible/roles/microk8s/tasks/microk8s/encryption.yml b/ansible/roles/microk8s/tasks/microk8s/encryption.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/roles/microk8s/tasks/setupenv/main.yml b/ansible/roles/microk8s/tasks/setupenv/main.yml index 3a29c3b..05f3866 100644 --- a/ansible/roles/microk8s/tasks/setupenv/main.yml +++ b/ansible/roles/microk8s/tasks/setupenv/main.yml @@ -25,7 +25,7 @@ - name: Check if secret exists ansible.builtin.shell: | set -o pipefail - microk8s.kubectl -n {{ item.namespace | default('default') }} get secret | grep {{ item.username }}-token | wc -l | awk '{ print $1 }' + microk8s.kubectl -n {{ item.namespace | default('default') }} get secret | grep {{ item.username }}-token | wc -l | awk '{ print $1 }' args: executable: /bin/bash register: secret_exists @@ -41,7 +41,7 @@ - name: Get the secret name ansible.builtin.shell: | set -o pipefail - microk8s.kubectl -n {{ item.namespace | default('default') }} get secret | grep {{ item.username }}-token | awk '{ print $1 }' + microk8s.kubectl -n {{ item.namespace | default('default') }} get secret | grep {{ item.username }}-token | awk '{ print $1 }' args: executable: /bin/bash register: secret_name @@ -53,7 +53,7 @@ - name: Describe the secret and extract the token ansible.builtin.shell: | set -o pipefail - microk8s.kubectl -n {{ item.namespace | default('default') }} describe secret {{ secret_name.stdout }} | grep token: | awk '{ print $2 }' + microk8s.kubectl -n {{ item.namespace | default('default') }} describe secret {{ secret_name.stdout }} | grep token: | awk '{ print $2 }' args: executable: /bin/bash register: token @@ -103,7 +103,7 @@ - k8s::users - name: Get new config SHA1 - set_fact: + ansible.builtin.set_fact: patched_kubeconfig_sha1: "{{ patched_kubeconfig_yaml | to_nice_yaml | sha1 }}" tags: - k8s::users @@ -115,6 +115,6 @@ dest: "{{ user_registered.home }}/.kube/config" owner: "{{ item.username }}" mode: "0600" - when: kubeconfig_exists.stat.exists == false or patched_kubeconfig_sha1 != kubeconfig_exists.stat.checksum + when: not kubeconfig_exists.stat.exists or patched_kubeconfig_sha1 != kubeconfig_exists.stat.checksum tags: - k8s::users diff --git a/ansible/roles/microk8s/templates/microk8s.yml.j2 b/ansible/roles/microk8s/templates/microk8s.yml.j2 new file mode 100644 index 0000000..7782af9 --- /dev/null +++ b/ansible/roles/microk8s/templates/microk8s.yml.j2 @@ -0,0 +1,12 @@ +--- +apiVersion: apiserver.config.k8s.io/v1 +kind: EncryptionConfiguration +resources: + - resources: + - secrets + providers: + - aescbc: + keys: + - name: k8s-crypto + secret: {{ secret }} + - identity: {} diff --git a/resources/iac_user,yaml b/resources/iac_user,yaml deleted file mode 100644 index a0486d2..0000000 --- a/resources/iac_user,yaml +++ /dev/null @@ -1,141 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: collabora - name: admin-collabora -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: gitea - name: admin-gitea -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: m3uproxy - name: admin-m3uproxy -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: nextcloud - name: admin-nextcloud -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: wordpress - name: admin-wordpress -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: namespace-creator -rules: - - apiGroups: [""] - resources: ["namespaces"] - verbs: ["create", "get", "list"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: admin-collabora-binding - namespace: collabora -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: admin-collabora - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: admin-gitea-binding - namespace: gitea -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: admin-gitea - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: admin-m3uproxy-binding - namespace: m3uproxy -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: admin-m3uproxy - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: admin-nextcloud-binding - namespace: nextcloud -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: admin-nextcloud - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: admin-wordpress-binding - namespace: wordpress -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: admin-wordpress - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: namespace-creator-binding -subjects: - - kind: User - name: iac - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: namespace-creator - apiGroup: rbac.authorization.k8s.io diff --git a/terraform/iac/buckets.tf b/terraform/iac/buckets.tf index cd3ffba..9ab2533 100644 --- a/terraform/iac/buckets.tf +++ b/terraform/iac/buckets.tf @@ -46,7 +46,7 @@ resource "scaleway_object_bucket_policy" "policy" { resource "scaleway_object" "encryption_key" { bucket = scaleway_object_bucket.infra_assets.id - key = "keys/${data.contabo_instance.microk8s.mac_address}.key" + key = "keys/${replace(data.contabo_instance.microk8s.mac_address, ":", "_")}.key" content_base64 = base64encode(var.encryption_key) }