diff --git a/group_vars/all/vars.yml b/group_vars/all/vars.yml index ae464f6..01a36fd 100644 --- a/group_vars/all/vars.yml +++ b/group_vars/all/vars.yml @@ -1,7 +1,7 @@ # vim: ft=yaml.ansible # code: language=ansible --- -encrypted_fs: /data +data_fs: /data hostname: "{{ inventory_hostname }}" timezone: Europe/Copenhagen diff --git a/group_vars/app_prod/vars.yml b/group_vars/app_prod/vars.yml index 9ee1f9e..2e57025 100644 --- a/group_vars/app_prod/vars.yml +++ b/group_vars/app_prod/vars.yml @@ -1,5 +1,7 @@ # vim: ft=yaml.ansible # code: language=ansible --- +apps_base_domain: sapti.me + db_inventory_hostname: sapt-labp-db01 db_host: "{{ hostvars[db_inventory_hostname].fqdn }}" diff --git a/group_vars/appservers/vars.yml b/group_vars/appservers/vars.yml index 2f2e06a..fb93771 100644 --- a/group_vars/appservers/vars.yml +++ b/group_vars/appservers/vars.yml @@ -1,9 +1,6 @@ # vim: ft=yaml.ansible # code: language=ansible --- -apps_data_root: "{{ encrypted_fs }}/apps" -docker_data_root: "{{ encrypted_fs }}/docker" - redis_passwords: nextcloud: "{{ vault_redis_passwords.nextcloud }}" diff --git a/group_vars/dbservers/vars.yml b/group_vars/dbservers/vars.yml deleted file mode 100644 index 64d6493..0000000 --- a/group_vars/dbservers/vars.yml +++ /dev/null @@ -1,4 +0,0 @@ -# vim: ft=yaml.ansible -# code: language=ansible ---- -postgresql_pgdata: "{{ encrypted_fs }}/pgsql/{{ postgresql_version }}/data" diff --git a/inventory.ini b/inventory.ini index 019958c..7680bd9 100644 --- a/inventory.ini +++ b/inventory.ini @@ -16,7 +16,7 @@ sapt-labs-db01 ansible_host=192.168.17.60 sapt-labr-prx01 ansible_host=192.168.17.10 sapt-labr-prx02 ansible_host=192.168.17.11 -[monitoring_shrd] +[monitor_shrd] sapt-labr-mon01 ansible_host=192.168.17.20 [proxmox_infra] @@ -45,6 +45,12 @@ app_stage db_prod db_stage +[proxyservers:children] +proxy_shrd + +[monitorservers:children] +monitor_shrd + [virtualservers:children] production staging diff --git a/roles/apps/defaults/main.yml b/roles/apps/defaults/main.yml index fee233c..b41168c 100644 --- a/roles/apps/defaults/main.yml +++ b/roles/apps/defaults/main.yml @@ -1,9 +1,8 @@ # vim: ft=yaml.ansible # code: language=ansible --- -apps_base_domain: sapti.me +apps_data_root: "{{ data_fs }}/apps" apps_local_domain: local.{{ apps_base_domain }} -apps_data_root: /apps apps_shared_docker_network: apps_network apps_postfix_docker_network: postfix_network @@ -61,7 +60,7 @@ apps_vars: backup: false sender: false extra_tasks: false - version: '1.7.0' + version: '1.7.1' apps_include: "{{ apps_vars | dict2items | map(attribute='key') | list }}" apps_backup: "{{ apps_vars | dict2items | selectattr('value.backup', 'true') | map(attribute='key') | list | intersect(apps_include) }}" diff --git a/roles/docker/defaults/main.yml b/roles/docker/defaults/main.yml deleted file mode 100644 index 09f1aad..0000000 --- a/roles/docker/defaults/main.yml +++ /dev/null @@ -1,4 +0,0 @@ -# vim: ft=yaml.ansible -# code: language=ansible ---- -docker_data_root: /var/lib/docker diff --git a/roles/docker/templates/etc/docker/daemon.json.j2 b/roles/docker/files/etc/docker/daemon.json similarity index 53% rename from roles/docker/templates/etc/docker/daemon.json.j2 rename to roles/docker/files/etc/docker/daemon.json index f7cbd2b..0d8b6e7 100644 --- a/roles/docker/templates/etc/docker/daemon.json.j2 +++ b/roles/docker/files/etc/docker/daemon.json @@ -1,5 +1,4 @@ { - "data-root": "{{ docker_data_root }}", "experimental": true, "ip6tables": true } diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml index 2356c1a..98210e9 100644 --- a/roles/docker/tasks/main.yml +++ b/roles/docker/tasks/main.yml @@ -28,8 +28,8 @@ state: present - name: Copy Docker daemon config file - ansible.builtin.template: - src: etc/docker/daemon.json.j2 + ansible.builtin.copy: + src: etc/docker/daemon.json dest: /etc/docker/daemon.json owner: root mode: u=rw,g=r,o=r diff --git a/roles/postgresql/defaults/main.yml b/roles/postgresql/defaults/main.yml index ca121a5..eb9f3d7 100644 --- a/roles/postgresql/defaults/main.yml +++ b/roles/postgresql/defaults/main.yml @@ -1,7 +1,5 @@ # vim: ft=yaml.ansible # code: language=ansible --- -postgresql_version: 16 -postgresql_pgdata_default: /var/lib/pgsql/{{ postgresql_version }}/data -postgresql_pgdata: "{{ postgresql_pgdata_default }}" +postgresql_pgdata: "{{ data_fs }}/pgsql/{{ postgresql_version }}/data" postgresql_service: postgresql-{{ postgresql_version }} diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml index 56ba5a5..2a9e4f8 100644 --- a/roles/postgresql/tasks/main.yml +++ b/roles/postgresql/tasks/main.yml @@ -23,7 +23,7 @@ - python{{ ansible_python.version.major }}-psycopg2 state: present -- name: Create PostgreSQL service override directory +- name: Create PostgreSQL service override folder ansible.builtin.file: path: /etc/systemd/system/{{ postgresql_service }}.service.d owner: root @@ -36,12 +36,18 @@ dest: /etc/systemd/system/{{ postgresql_service }}.service.d/override.conf owner: root mode: u=rw,g=r,o=r - when: postgresql_pgdata != postgresql_pgdata_default notify: Reload systemd - name: Flush handlers ansible.builtin.meta: flush_handlers +- name: Create PGDATA folder + ansible.builtin.file: + path: "{{ postgresql_pgdata }}" + owner: root + mode: u=rwx,g=rx,o=rx + state: directory + - name: Initialize database ansible.builtin.command: cmd: /usr/pgsql-{{ postgresql_version }}/bin/postgresql-{{ postgresql_version }}-setup initdb diff --git a/roles/proxy/defaults/main.yml b/roles/proxy/defaults/main.yml index 1f18a61..1db1cf9 100644 --- a/roles/proxy/defaults/main.yml +++ b/roles/proxy/defaults/main.yml @@ -1,8 +1,8 @@ # vim: ft=yaml.ansible # code: language=ansible --- -proxy_data_root: /proxy -proxy_mode: global +proxy_data_root: "{{ data_fs }}/proxy" +proxy_caddy_version: '2.7.4' proxy_vars: production: diff --git a/roles/proxy/handlers/main.yml b/roles/proxy/handlers/main.yml new file mode 100644 index 0000000..365af72 --- /dev/null +++ b/roles/proxy/handlers/main.yml @@ -0,0 +1,8 @@ +# vim: ft=yaml.ansible +# code: language=ansible +--- +- name: Build custom Docker image for Caddy + ansible.builtin.command: + cmd: docker compose build + chdir: "{{ proxy_data_root }}/{{ proxy_mode }}" + warn: false diff --git a/roles/proxy/tasks/main.yml b/roles/proxy/tasks/main.yml index aa2d1e2..e73e553 100644 --- a/roles/proxy/tasks/main.yml +++ b/roles/proxy/tasks/main.yml @@ -1,9 +1,69 @@ # vim: ft=yaml.ansible # code: language=ansible --- +- name: Create base folder + ansible.builtin.file: + path: "{{ proxy_data_root }}" + owner: root + mode: u=rwx,g=rx,o=rx + state: directory + +- name: Create folder for Caddy + ansible.builtin.file: + path: "{{ proxy_data_root }}/{{ proxy_mode }}" + owner: root + mode: u=rwx,go= + state: directory + +- name: Create build folder for Caddy + ansible.builtin.file: + path: "{{ proxy_data_root }}/{{ proxy_mode }}/build" + owner: root + mode: u=rwx,g=rx,o=rx + state: directory + +- name: Copy Compose file for Caddy + ansible.builtin.template: + src: docker/docker-compose.yml.j2 + dest: "{{ proxy_data_root }}/{{ proxy_mode }}/docker-compose.yml" + owner: root + mode: u=rw,go= + +- name: Copy Dockerfile for Caddy + ansible.builtin.template: + src: docker/Dockerfile.j2 + dest: "{{ proxy_data_root }}/{{ proxy_mode }}/build/Dockerfile" + owner: root + mode: u=rw,g=r,o=r + notify: Build custom Docker image for Caddy + +- name: Create data folder for Caddy + ansible.builtin.file: + path: "{{ proxy_data_root }}/{{ proxy_mode }}/data" + owner: root + mode: u=rwx,g=rx,o=rx + state: directory + - name: Copy Caddyfile ansible.builtin.template: src: caddy/{{ proxy_mode }}.Caddyfile.j2 - dest: "{{ proxy_data_root }}/caddy/data/Caddyfile" + dest: "{{ proxy_data_root }}/{{ proxy_mode }}/data/Caddyfile" owner: root mode: u=rw,go= + +- name: Create subfolders for Caddy data + ansible.builtin.file: + path: "{{ proxy_data_root }}/{{ proxy_mode }}/data/caddy-{{ item }}" + owner: root + mode: u=rwx,go= + state: directory + loop: + - config + - data + +- name: Copy deploy.sh + ansible.builtin.template: + src: scripts/deploy.sh.j2 + dest: /usr/local/bin/deploy.sh + owner: root + mode: u=rwx,g=rx,o=rx diff --git a/roles/proxy/templates/docker/Dockerfile.j2 b/roles/proxy/templates/docker/Dockerfile.j2 new file mode 100644 index 0000000..b8a8ef3 --- /dev/null +++ b/roles/proxy/templates/docker/Dockerfile.j2 @@ -0,0 +1,7 @@ +# code: language=ansible-jinja +FROM caddy:{{ proxy_caddy_version }}-builder-alpine AS builder +RUN xcaddy build v{{ proxy_caddy_version }} \ + --with github.com/caddy-dns/njalla + +FROM caddy:{{ proxy_caddy_version }}-alpine +COPY --from=builder /usr/bin/caddy /usr/bin/caddy \ No newline at end of file diff --git a/roles/proxy/templates/docker/docker-compose.yml b/roles/proxy/templates/docker/docker-compose.yml new file mode 100644 index 0000000..a16ca1f --- /dev/null +++ b/roles/proxy/templates/docker/docker-compose.yml @@ -0,0 +1,19 @@ +# code: language=ansible-jinja +version: "3.8" + +services: + caddy: + image: custom/caddy:{{ proxy_caddy_version }}-alpine + build: + context: ./build + restart: always + network_mode: host + volumes: + - "./data/Caddyfile:/etc/caddy/Caddyfile:ro" + - "./data/caddy-config:/config:rw" + - "./data/caddy-data:/data:rw" + cap_add: + - net_bind_service + - dac_override + cap_drop: + - all \ No newline at end of file diff --git a/roles/proxy/templates/scripts/deploy.sh.j2 b/roles/proxy/templates/scripts/deploy.sh.j2 new file mode 100644 index 0000000..94acc0e --- /dev/null +++ b/roles/proxy/templates/scripts/deploy.sh.j2 @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# code: language=bash + +ARG="$1" +PROXY_DIR="{{ proxy_data_root }}/{{ proxy_mode }}" + +case $ARG in +start) + docker compose -f $PROXY_DIR/docker-compose.yml up --remove-orphans -d + ;; +stop) + docker compose -f $PROXY_DIR/docker-compose.yml down --remove-orphans + ;; +restart) + docker compose -f $PROXY_DIR/docker-compose.yml restart + ;; +*) + echo "Unrecognized argument" + exit 1 + ;; +esac diff --git a/roles/vm-common/tasks/base.yml b/roles/vm-common/tasks/base.yml index 9305f4a..79c8ad3 100644 --- a/roles/vm-common/tasks/base.yml +++ b/roles/vm-common/tasks/base.yml @@ -16,25 +16,6 @@ owner: root mode: u=rw,g=r,o=r -- name: Disable systemd-resolved stub resolver - when: hostname in groups['control_infra'] - block: - - name: Set /etc/resolv.conf symlink - ansible.builtin.file: - path: /etc/resolv.conf - src: /run/systemd/resolve/resolv.conf - owner: root - force: true - state: link - - - name: Set DNSStubListener=no - ansible.builtin.lineinfile: - path: /etc/systemd/resolved.conf - regexp: '^#?DNSStubListener=' - line: 'DNSStubListener=no' - state: present - notify: Restart systemd-resolved - - name: Enable extra repositories ansible.builtin.dnf: name: diff --git a/roles/vm-common/tasks/firewall.yml b/roles/vm-common/tasks/firewall.yml index 3ed24e1..a3e4576 100644 --- a/roles/vm-common/tasks/firewall.yml +++ b/roles/vm-common/tasks/firewall.yml @@ -4,19 +4,29 @@ - name: General firewall rules notify: Reload firewalld block: - - name: Move main LAN and VPN networks to zone 'drop' + - name: Move Guest LAN and and IoT LAN networks to zone 'drop' ansible.posix.firewalld: zone: drop source: "{{ item }}" permanent: true state: enabled + loop: + - 192.168.2.0/24 + - 192.168.4.0/24 + + - name: Move Home LAN and VPN networks to zone 'dmz' + ansible.posix.firewalld: + zone: dmz + source: "{{ item }}" + permanent: true + state: enabled loop: - 192.168.1.0/24 - 192.168.8.0/24 - - name: Move lab network to zone 'dmz' + - name: Move Lab LAN network to zone 'public' ansible.posix.firewalld: - zone: dmz + zone: public source: 192.168.17.0/24 permanent: true state: enabled @@ -28,32 +38,35 @@ permanent: true state: enabled - - name: Default deny incoming connections to SSH port in zones 'dmz' and 'internal' + - name: Default deny incoming connections to SSH port in all zones ansible.posix.firewalld: zone: "{{ item }}" service: ssh permanent: true state: disabled loop: + - drop - dmz + - public - internal # Until sapt-labx-ctl01 is deployed - - name: Allow incoming connections to SSH port in zone 'drop' + - name: Allow incoming connections to SSH port in zone 'dmz' ansible.posix.firewalld: - zone: drop + zone: dmz service: ssh permanent: true state: enabled # When sapt-labx-ctl01 is deployed - # - name: Allow incoming connections from jump host to SSH port in zone 'dmz' + # - name: Allow incoming connections from control machines to SSH port in zone 'public' # ansible.posix.firewalld: - # zone: dmz - # source: "{{ hostvars['sapt-labx-ctl01'].ansible_host }}" + # zone: public + # source: "{{ hostvars[item].ansible_host }}" # service: ssh # permanent: true # state: enabled + # loop: "{{ groups['control_infra'] }}" - name: Firewall rules for production and staging loop: @@ -61,6 +74,7 @@ - stage loop_control: loop_var: env + when: hostname in groups['production'] or hostname in groups['staging'] notify: Reload firewalld block: - name: Allow incoming connections from app servers to PostgreSQL port in zone 'internal' @@ -73,5 +87,39 @@ loop: "{{ groups['app_' + env] }}" when: hostname in groups['db_' + env] +- name: Firewall rules for proxy servers + when: hostname in group['proxyservers'] + notify: Reload firewalld + block: + - name: Allow incoming connections to HTTP port in zones 'drop' and 'dmz' + ansible.posix.firewalld: + zone: "{{ item }}" + service: http + permanent: true + state: enabled + loop: + - drop + - dmz + + - name: Allow incoming connections to HTTPS port in zones 'drop' and 'dmz' + ansible.posix.firewalld: + zone: "{{ item }}" + service: https + permanent: true + state: enabled + loop: + - drop + - dmz + + - name: Allow incoming connections to HTTP/3 port in zones 'drop' and 'dmz' + ansible.posix.firewalld: + zone: "{{ item }}" + service: http3 + permanent: true + state: enabled + loop: + - drop + - dmz + - name: Flush handlers ansible.builtin.meta: flush_handlers diff --git a/roles/vm-common/templates/etc/hosts.j2 b/roles/vm-common/templates/etc/hosts.j2 index 366a8e7..04405ba 100644 --- a/roles/vm-common/templates/etc/hosts.j2 +++ b/roles/vm-common/templates/etc/hosts.j2 @@ -1,6 +1,6 @@ # code: language=ansible-jinja 127.0.0.1 localhost -127.0.1.1 {{ fqdn }} +127.0.1.1 {{ hostname }} {{ fqdn }} # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback diff --git a/site.yml b/site.yml index 09531ac..02cb54f 100644 --- a/site.yml +++ b/site.yml @@ -19,3 +19,10 @@ remote_user: ansible roles: - postgresql + +- name: Proxy servers + hosts: proxyservers + remote_user: ansible + roles: + - docker + - proxy