From 9e227d132af75e474f7ade56e4186c630e3ba496 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Mon, 26 Sep 2022 23:10:48 +0200 Subject: [PATCH] Playbooks to deploy pod-rproxy and pod-www --- group_vars/.template | 7 ++ host_vars/.template | 7 ++ .../{hostname.j2 => _hostname.j2} | 0 .../etc/network/interfaces.d/veth-_service.j2 | 19 +++++ .../system/connect-pod-service@.path.j2 | 5 ++ .../system/connect-pod-service@.service | 7 ++ .../.config/containers/containers.conf.j2 | 2 + .../.config/containers/storage.conf.j2 | 6 ++ .../.config/pod-rproxy/certbot.cron | 11 +++ .../nginx-conf.d/wojciechkozlowski.eu.conf | 57 +++++++++++++ .../pod-rproxy/.config/pod-rproxy/nginx.conf | 58 +++++++++++++ .../user/container-rproxy-certbot.service.j2 | 15 ++++ .../user/container-rproxy-certbot.timer.j2 | 15 ++++ .../user/container-rproxy-nginx.service.j2 | 21 +++++ .../systemd/user/pod-rproxy.service.j2 | 24 ++++++ .../user/container-www-nginx.service.j2 | 21 +++++ .../.config/systemd/user/pod-www.service.j2 | 24 ++++++ playbooks/services.yml | 16 ++++ playbooks/tasks/hosts/logs.yml | 2 +- playbooks/tasks/hosts/utils.yml | 1 + playbooks/tasks/services/00-podman.yml | 10 +++ playbooks/tasks/services/01-hosts.yml | 7 ++ playbooks/tasks/services/02-directories.yml | 23 ++++++ playbooks/tasks/services/03-service.yml | 4 + playbooks/tasks/services/service/00-vars.yml | 25 ++++++ playbooks/tasks/services/service/01-user.yml | 81 +++++++++++++++++++ playbooks/tasks/services/service/02-veth.yml | 41 ++++++++++ .../services/service/03-pod.d/rproxy.yml | 20 +++++ .../tasks/services/service/03-pod.d/www.yml | 28 +++++++ playbooks/tasks/services/service/03-pod.yml | 78 ++++++++++++++++++ playbooks/tasks/vpn/bridge.yml | 7 +- playbooks/tasks/vpn/wireguard.yml | 7 +- 32 files changed, 646 insertions(+), 3 deletions(-) rename playbooks/filesystem/common/etc/logcheck/ignore.d.server/{hostname.j2 => _hostname.j2} (100%) create mode 100644 playbooks/filesystem/common/etc/network/interfaces.d/veth-_service.j2 create mode 100644 playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.path.j2 create mode 100644 playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.service create mode 100644 playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/containers.conf.j2 create mode 100644 playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/storage.conf.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/certbot.cron create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx-conf.d/wojciechkozlowski.eu.conf create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx.conf create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.service.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.timer.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-nginx.service.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/pod-rproxy.service.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/container-www-nginx.service.j2 create mode 100644 playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/pod-www.service.j2 create mode 100644 playbooks/services.yml create mode 100644 playbooks/tasks/services/00-podman.yml create mode 100644 playbooks/tasks/services/01-hosts.yml create mode 100644 playbooks/tasks/services/02-directories.yml create mode 100644 playbooks/tasks/services/03-service.yml create mode 100644 playbooks/tasks/services/service/00-vars.yml create mode 100644 playbooks/tasks/services/service/01-user.yml create mode 100644 playbooks/tasks/services/service/02-veth.yml create mode 100644 playbooks/tasks/services/service/03-pod.d/rproxy.yml create mode 100644 playbooks/tasks/services/service/03-pod.d/www.yml create mode 100644 playbooks/tasks/services/service/03-pod.yml diff --git a/group_vars/.template b/group_vars/.template index 232ae04..ee57562 100644 --- a/group_vars/.template +++ b/group_vars/.template @@ -17,3 +17,10 @@ postfix_smtp_user: vpn_wg0_port: vpn_wg0_netmask: vpn_wg0_preshared_key: + +# Service variables +services: { + name: { + address: X.X.X.X, + }, +} diff --git a/host_vars/.template b/host_vars/.template index 7b265f7..6bc3630 100644 --- a/host_vars/.template +++ b/host_vars/.template @@ -23,3 +23,10 @@ vpn_wg0_endpoint_address: vpn_remote_subnet: vpn_reverse_proxy_address: + +# Service variables +host_services: [ + service_name_1, + service_name_2, +] +service_bridge_gateway: diff --git a/playbooks/filesystem/common/etc/logcheck/ignore.d.server/hostname.j2 b/playbooks/filesystem/common/etc/logcheck/ignore.d.server/_hostname.j2 similarity index 100% rename from playbooks/filesystem/common/etc/logcheck/ignore.d.server/hostname.j2 rename to playbooks/filesystem/common/etc/logcheck/ignore.d.server/_hostname.j2 diff --git a/playbooks/filesystem/common/etc/network/interfaces.d/veth-_service.j2 b/playbooks/filesystem/common/etc/network/interfaces.d/veth-_service.j2 new file mode 100644 index 0000000..2a5a4d0 --- /dev/null +++ b/playbooks/filesystem/common/etc/network/interfaces.d/veth-_service.j2 @@ -0,0 +1,19 @@ +iface {{ service_iface_name }} inet manual + pre-up mkdir -p /run/netns + pre-up ln -sfTv /proc/$(cat /var/lib/{{ ansible_hostname }}/containers/{{ service_user_name }}/pidfile)/ns/net /run/netns/{{ service_user_name }} + + pre-up ip link add name $IFACE type veth peer name veth0 netns {{ service_user_name }} + pre-up ip link set $IFACE master br0 + + post-up ip -n {{ service_user_name }} link set veth0 up + post-up ip -n {{ service_user_name }} address add {{ service_bridge_address }}/24 dev veth0 + post-up ip -n {{ service_user_name }} route add default via {{ service_bridge_gateway }} dev veth0 + + pre-down ip -n {{ service_user_name }} route del default via {{ service_bridge_gateway }} dev veth0 + pre-down ip -n {{ service_user_name }} address del {{ service_bridge_address }}/24 dev veth0 + pre-down ip -n {{ service_user_name }} link set veth0 down + + post-down ip link set $IFACE nomaster + post-down ip link del dev $IFACE + + post-down rm /run/netns/{{ service_user_name }} diff --git a/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.path.j2 b/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.path.j2 new file mode 100644 index 0000000..09d7456 --- /dev/null +++ b/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.path.j2 @@ -0,0 +1,5 @@ +[Path] +PathModified=/var/lib/{{ ansible_hostname }}/containers/pod-%i/pidfile + +[Install] +WantedBy=multi-user.target network.target diff --git a/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.service b/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.service new file mode 100644 index 0000000..135873b --- /dev/null +++ b/playbooks/filesystem/common/etc/systemd/system/connect-pod-service@.service @@ -0,0 +1,7 @@ +[Unit] +Description=Connect %i to root bridge +After=network.target + +[Service] +Type=oneshot +ExecStart=/usr/bin/sh -c '/usr/sbin/ifdown --ignore-errors veth-%i || /usr/bin/true ; /usr/sbin/ifup veth-%i' diff --git a/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/containers.conf.j2 b/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/containers.conf.j2 new file mode 100644 index 0000000..699e405 --- /dev/null +++ b/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/containers.conf.j2 @@ -0,0 +1,2 @@ +[engine] +volume_path = "/var/lib/{{ ansible_hostname }}/data/{{ service_user_name }}" diff --git a/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/storage.conf.j2 b/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/storage.conf.j2 new file mode 100644 index 0000000..a28ecb0 --- /dev/null +++ b/playbooks/filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/storage.conf.j2 @@ -0,0 +1,6 @@ +[storage] +graphroot = "/var/lib/{{ ansible_hostname }}/containers/{{ service_user_name }}/storage" +driver = "overlay" + +[storage.options] +mount_program = "/usr/bin/fuse-overlayfs" diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/certbot.cron b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/certbot.cron new file mode 100644 index 0000000..ba05c48 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/certbot.cron @@ -0,0 +1,11 @@ +# /etc/cron.d/certbot: crontab entries for the certbot package +# +# Upstream recommends attempting renewal twice a day +# +# Eventually, this will be an opportunity to validate certificates +# haven't been revoked, etc. Renewal will only occur if expiration +# is within 30 days. +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +0 */12 * * * root perl -e 'sleep int(rand(3600))' && certbot -q renew --webroot-path /var/www/html diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx-conf.d/wojciechkozlowski.eu.conf b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx-conf.d/wojciechkozlowski.eu.conf new file mode 100644 index 0000000..c5d1db0 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx-conf.d/wojciechkozlowski.eu.conf @@ -0,0 +1,57 @@ +server { + listen 80; + server_name wojciechkozlowski.eu www.wojciechkozlowski.eu; + + location ^~ /.well-known { + allow all; + root /var/www/html; + } + + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl; + server_name wojciechkozlowski.eu; + + ssl_certificate /etc/letsencrypt/live/wojciechkozlowski.eu/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/wojciechkozlowski.eu/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/wojciechkozlowski.eu/chain.pem; + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + proxy_pass http://pod-www; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + +} + +server { + listen 443 ssl; + server_name www.wojciechkozlowski.eu; + + ssl_certificate /etc/letsencrypt/live/www.wojciechkozlowski.eu/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/www.wojciechkozlowski.eu/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/www.wojciechkozlowski.eu/chain.pem; + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Host $host; + proxy_pass http://pod-www; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + +} diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx.conf b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx.conf new file mode 100644 index 0000000..003f424 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/pod-rproxy/nginx.conf @@ -0,0 +1,58 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + # Configuration based on https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html. + + # SSL protocols. + ssl_protocols TLSv1.2 TLSv1.3; + + # Ciphers suite based on intermediate list from + # https://wiki.mozilla.org/Security/Server_Side_TLS. To verify OpenSSL names, use + # https://raw.githubusercontent.com/openssl/openssl/master/include/openssl/tls1.h. + ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + + # Prefer server's settings. + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + # Diffie Hellman Ephemeral Parameters: `openssl dhparam -out dhparam.pem 4096`. + ssl_dhparam /etc/ssl/certs/dhparam.pem; + ssl_ecdh_curve secp384r1; + + # OCSP Stapling. + ssl_stapling on; + ssl_stapling_verify on; + resolver 1.1.1.1 1.0.0.1 valid=300s; + resolver_timeout 5s; + + # HTTP Strict Transport Security. + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; " always; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.service.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.service.j2 new file mode 100644 index 0000000..9035afb --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Podman container-rproxy-certbot.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +BindsTo=pod-rproxy.service +After=pod-rproxy.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/container-rproxy-certbot.pid %t/container-rproxy-certbot.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-rproxy-certbot.pid --cidfile %t/container-rproxy-certbot.ctr-id --cgroups=no-conmon --pod-id-file %t/pod-rproxy.pod-id --replace -v ./.config/pod-rproxy/certbot.cron:/etc/cron.d/certbot:ro -v etc_letsencrypt:/etc/letsencrypt -v var_lib_letsencrypt:/var/lib/letsencrypt -v ./.config/pod-rproxy/html:/var/www/html --name=pod-rproxy-certbot docker.io/certbot/certbot --non-interactive renew --webroot-path /var/www/html +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-rproxy-certbot.ctr-id +Type=exec diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.timer.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.timer.j2 new file mode 100644 index 0000000..5f4b285 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-certbot.timer.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Renew certificates with certbot +Documentation=man:certbot(1) +Wants=network.target +After=network-online.target +BindsTo=pod-rproxy.service +After=pod-rproxy.service + +[Timer] +OnCalendar=*-*-* 06,18:00:00 +Persistent=true +RandomizedDelaySec=1h + +[Install] +WantedBy=timers.target diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-nginx.service.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-nginx.service.j2 new file mode 100644 index 0000000..1aee8b4 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/container-rproxy-nginx.service.j2 @@ -0,0 +1,21 @@ +[Unit] +Description=Podman container-rproxy-nginx.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +BindsTo=pod-rproxy.service +After=pod-rproxy.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/container-rproxy-nginx.pid %t/container-rproxy-nginx.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-rproxy-nginx.pid --cidfile %t/container-rproxy-nginx.ctr-id --cgroups=no-conmon --pod-id-file %t/pod-rproxy.pod-id --replace -dt {{ service_rproxy_hosts }} -v ./.config/pod-rproxy/nginx.conf:/etc/nginx/nginx.conf:ro -v ./.config/pod-rproxy/nginx-conf.d:/etc/nginx/conf.d:ro -v ./.config/pod-rproxy/dhparam.pem:/etc/ssl/certs/dhparam.pem:ro -v etc_letsencrypt:/etc/letsencrypt:ro -v var_lib_letsencrypt:/var/lib/letsencrypt:ro -v ./.config/pod-rproxy/html:/var/www/html --name=pod-rproxy-nginx docker.io/library/nginx +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-rproxy-nginx.ctr-id -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-rproxy-nginx.ctr-id +PIDFile=%t/container-rproxy-nginx.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/pod-rproxy.service.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/pod-rproxy.service.j2 new file mode 100644 index 0000000..3580e3a --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-rproxy/.config/systemd/user/pod-rproxy.service.j2 @@ -0,0 +1,24 @@ +[Unit] +Description=Podman pod-rproxy.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +Requires=container-rproxy-nginx.service container-rproxy-certbot.timer +Before=container-rproxy-nginx.service container-rproxy-certbot.timer + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f /var/lib/{{ ansible_hostname }}/containers/pod-rproxy/pidfile +ExecStartPre=/bin/rm -f %t/pod-rproxy.pid %t/pod-rproxy.pod-id +ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-rproxy.pid --pod-id-file %t/pod-rproxy.pod-id --name=rproxy --network=none --replace +ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-rproxy.pod-id +ExecStartPost=/usr/bin/sh -c 'podman inspect --format "{% raw %}{{ .State.Pid }}{% endraw %}" $(podman inspect --format "{% raw %}{{ .InfraContainerID }}{% endraw %}" rproxy) > /var/lib/{{ ansible_hostname }}/containers/pod-rproxy/pidfile' +ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-rproxy.pod-id -t 10 +ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-rproxy.pod-id +PIDFile=%t/pod-rproxy.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/container-www-nginx.service.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/container-www-nginx.service.j2 new file mode 100644 index 0000000..28fa6c5 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/container-www-nginx.service.j2 @@ -0,0 +1,21 @@ +[Unit] +Description=Podman container-www-nginx.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +BindsTo=pod-www.service +After=pod-www.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f %t/container-www-nginx.pid %t/container-www-nginx.ctr-id +ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-www-nginx.pid --cidfile %t/container-www-nginx.ctr-id --cgroups=no-conmon --pod-id-file %t/pod-www.pod-id --replace -dt -v ./.config/pod-www/wojciechkozlowski.eu/public:/usr/share/nginx/html:ro --name=pod-www-nginx docker.io/library/nginx +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-www-nginx.ctr-id -t 10 +ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-www-nginx.ctr-id +PIDFile=%t/container-www-nginx.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target diff --git a/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/pod-www.service.j2 b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/pod-www.service.j2 new file mode 100644 index 0000000..4d28ef9 --- /dev/null +++ b/playbooks/filesystem/valkyrie/var/lib/valkyrie/home/pod-www/.config/systemd/user/pod-www.service.j2 @@ -0,0 +1,24 @@ +[Unit] +Description=Podman pod-www.service +Documentation=man:podman-generate-systemd(1) +Wants=network.target +After=network-online.target +Requires=container-www-nginx.service +Before=container-www-nginx.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +ExecStartPre=/bin/rm -f /var/lib/{{ ansible_hostname }}/containers/pod-www/pidfile +ExecStartPre=/bin/rm -f %t/pod-www.pid %t/pod-www.pod-id +ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-www.pid --pod-id-file %t/pod-www.pod-id --name=rproxy --network=none --replace +ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-www.pod-id +ExecStartPost=/usr/bin/sh -c 'podman inspect --format "{% raw %}{{ .State.Pid }}{% endraw %}" $(podman inspect --format "{% raw %}{{ .InfraContainerID }}{% endraw %}" rproxy) > /var/lib/{{ ansible_hostname }}/containers/pod-www/pidfile' +ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-www.pod-id -t 10 +ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-www.pod-id +PIDFile=%t/pod-www.pid +Type=forking + +[Install] +WantedBy=multi-user.target default.target diff --git a/playbooks/services.yml b/playbooks/services.yml new file mode 100644 index 0000000..95efb19 --- /dev/null +++ b/playbooks/services.yml @@ -0,0 +1,16 @@ +--- +- name: "Deploy services" + # Before applying this to yggdrasil need handle zfs datasets + hosts: valkyrie + + vars: + - service_rproxy_hosts: + + tasks: + - import_tasks: tasks/services/00-podman.yml + - import_tasks: tasks/services/01-hosts.yml + - import_tasks: tasks/services/02-directories.yml + - include_tasks: tasks/services/03-service.yml + with_items: "{{ host_services }}" + loop_control: + loop_var: service_name diff --git a/playbooks/tasks/hosts/logs.yml b/playbooks/tasks/hosts/logs.yml index 5fe67ab..6fe32a8 100644 --- a/playbooks/tasks/hosts/logs.yml +++ b/playbooks/tasks/hosts/logs.yml @@ -12,7 +12,7 @@ - name: Configure logcheck ignores template: - src: ./filesystem/common/etc/logcheck/ignore.d.server/hostname.j2 + src: ./filesystem/common/etc/logcheck/ignore.d.server/_hostname.j2 dest: /etc/logcheck/ignore.d.server/{{ ansible_hostname }} group: logcheck mode: 0644 diff --git a/playbooks/tasks/hosts/utils.yml b/playbooks/tasks/hosts/utils.yml index d4f82a5..aefa9e6 100644 --- a/playbooks/tasks/hosts/utils.yml +++ b/playbooks/tasks/hosts/utils.yml @@ -1,6 +1,7 @@ - name: Install utility programs apt: name: + - acl - git - htop - man diff --git a/playbooks/tasks/services/00-podman.yml b/playbooks/tasks/services/00-podman.yml new file mode 100644 index 0000000..f7c7365 --- /dev/null +++ b/playbooks/tasks/services/00-podman.yml @@ -0,0 +1,10 @@ +- name: Install podman + apt: + name: podman + register: podman_install + +# Required for podman. +- name: Reboot machine + reboot: + when: + podman_install is changed diff --git a/playbooks/tasks/services/01-hosts.yml b/playbooks/tasks/services/01-hosts.yml new file mode 100644 index 0000000..917fa85 --- /dev/null +++ b/playbooks/tasks/services/01-hosts.yml @@ -0,0 +1,7 @@ +- name: Collect reverse proxy hosts + set_fact: + service_rproxy_hosts: "{{ service_rproxy_hosts }} --add-host=pod-{{ item.key }}:{{ item.value.address }}" + with_items: "{{ services | dict2items }}" + +- debug: + msg: "{{ service_rproxy_hosts }}" diff --git a/playbooks/tasks/services/02-directories.yml b/playbooks/tasks/services/02-directories.yml new file mode 100644 index 0000000..fd22856 --- /dev/null +++ b/playbooks/tasks/services/02-directories.yml @@ -0,0 +1,23 @@ +- name: Create service directory + file: + path: /var/lib/{{ ansible_hostname }} + state: directory + mode: 0755 + +- name: Create service container directory + file: + path: /var/lib/{{ ansible_hostname }}/containers + state: directory + mode: 0755 + +- name: Create service data directory + file: + path: /var/lib/{{ ansible_hostname }}/data + state: directory + mode: 0755 + +- name: Create service home directory + file: + path: /var/lib/{{ ansible_hostname }}/home + state: directory + mode: 0755 diff --git a/playbooks/tasks/services/03-service.yml b/playbooks/tasks/services/03-service.yml new file mode 100644 index 0000000..995c944 --- /dev/null +++ b/playbooks/tasks/services/03-service.yml @@ -0,0 +1,4 @@ +- import_tasks: service/00-vars.yml +- import_tasks: service/01-user.yml +- import_tasks: service/02-veth.yml +- import_tasks: service/03-pod.yml diff --git a/playbooks/tasks/services/service/00-vars.yml b/playbooks/tasks/services/service/00-vars.yml new file mode 100644 index 0000000..5844a51 --- /dev/null +++ b/playbooks/tasks/services/service/00-vars.yml @@ -0,0 +1,25 @@ +- name: Set service variables + set_fact: + service_user_name: "pod-{{ service_name }}" + service_iface_name: "veth-{{ service_name }}" + service_bridge_address: "{{ services[service_name].address }}" + service_changed: false + +- name: Set service variables + set_fact: + service_home: "/var/lib/{{ ansible_hostname }}/home/{{ service_user_name }}" + +- name: Set service variables + set_fact: + local_service_home: "./filesystem/{{ ansible_hostname }}/{{ service_home }}" + +- name: Print service variables + debug: + msg: + - "service_name: {{ service_name }}" + - "service_user_name: {{ service_user_name }}" + - "service_iface_name: {{ service_iface_name }}" + - "service_bridge_address: {{ service_bridge_address }}" + - "service_changed: {{ service_changed }}" + - "service_home: {{ service_home }}" + - "local_service_home: {{ local_service_home }}" diff --git a/playbooks/tasks/services/service/01-user.yml b/playbooks/tasks/services/service/01-user.yml new file mode 100644 index 0000000..bf28fc7 --- /dev/null +++ b/playbooks/tasks/services/service/01-user.yml @@ -0,0 +1,81 @@ +- name: Create system user for {{ service_name }} + user: + name: "{{ service_user_name }}" + create_home: yes + home: "{{ service_home }}" + shell: /usr/sbin/nologin + system: yes + register: user_create + +- name: Configure subuids and subgids for user {{ service_user_name }} + shell: | + export NEW_SUBUID=$(($(tail -1 /etc/subuid | awk -F ":" '{print $2}')+65536)) + export NEW_SUBGID=$(($(tail -1 /etc/subgid | awk -F ":" '{print $2}')+65536)) + usermod --add-subuids ${NEW_SUBUID}-$((${NEW_SUBUID}+65535)) \ + --add-subgids ${NEW_SUBGID}-$((${NEW_SUBGID}+65535)) \ + {{ service_user_name }} + when: + user_create is changed + +- name: Ensure XDG_RUNTIME_DIR is set for user {{ service_user_name }} + shell: | + echo '\nexport XDG_RUNTIME_DIR=/run/user/$(id -u)' >> \ + {{ service_home }}/.bashrc + when: + user_create is changed + +- name: Enable lingering for user {{ service_user_name }} + command: loginctl enable-linger {{ service_user_name }} + when: + user_create is changed + +- name: Create container directory for user {{ service_user_name }} + file: + path: "/var/lib/{{ ansible_hostname }}/containers/{{ service_user_name }}" + state: directory + owner: "{{ service_user_name }}" + group: "{{ service_user_name }}" + mode: 0755 + +- name: Create volume data directory for user {{ service_user_name }} + file: + path: "/var/lib/{{ ansible_hostname }}/data/{{ service_user_name }}" + state: directory + owner: "{{ service_user_name }}" + group: "{{ service_user_name }}" + mode: 0755 + +- block: + - name: Create configuration directory for user {{ service_user_name }} + file: + path: "{{ service_home }}/.config" + state: directory + mode: 0755 + + - name: Create container configuration directory for user {{ service_user_name }} + file: + path: "{{ service_home }}/.config/containers" + state: directory + mode: 0755 + + - name: Configure storage.conf for user {{ service_user_name }} + template: + src: "./filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/storage.conf.j2" + dest: "{{ service_home }}/.config/containers/storage.conf" + mode: 0644 + register: user_containers_storage + + - name: Configure containers.conf for user {{ service_user_name }} + template: + src: "./filesystem/common/var/lib/_hostname/home/_service_user_name/.config/containers/containers.conf.j2" + dest: "{{ service_home }}/.config/containers/containers.conf" + mode: 0644 + register: user_containers_containers + + - name: Reset podman + shell: "cd $HOME; yes | podman system reset" + when: + user_containers_storage is changed or + user_containers_containers is changed + + become_user: "{{ service_user_name }}" diff --git a/playbooks/tasks/services/service/02-veth.yml b/playbooks/tasks/services/service/02-veth.yml new file mode 100644 index 0000000..1d9ed9c --- /dev/null +++ b/playbooks/tasks/services/service/02-veth.yml @@ -0,0 +1,41 @@ +- name: Configure veth interface for user {{ service_user_name }} + template: + src: "./filesystem/common/etc/network/interfaces.d/veth-_service.j2" + dest: "/etc/network/interfaces.d/{{ service_iface_name }}" + mode: 0644 + validate: > + bash -c + 'export NEWIF=%s; + if ! diff ${NEWIF} /etc/network/interfaces.d/{{ service_iface_name }} && + ip link show dev {{ service_iface_name }} ; + then + ifdown {{ service_iface_name }} && ifup -i ${NEWIF} {{ service_iface_name }} ; + fi' + register: veth_service_intf + +- name: Configure connect-pod-service + copy: + src: "./filesystem/common/etc/systemd/system/connect-pod-service@.service" + dest: "/etc/systemd/system/connect-pod-service@.service" + mode: 0644 + register: systemd_connect_pod_service_service + +- name: Configure connect-pod-service path trigger + template: + src: "./filesystem/common/etc/systemd/system/connect-pod-service@.path.j2" + dest: "/etc/systemd/system/connect-pod-service@.path" + mode: 0644 + register: systemd_connect_pod_service_path + +- name: SystemD daemon reload + systemd: + daemon_reload: true + when: + systemd_connect_pod_service_service is changed or + systemd_connect_pod_service_path is changed + +- name: Enable the path trigger service for {{ service_name }} + systemd: + name: "connect-pod-service@{{ service_name }}.path" + enabled: yes + state: started diff --git a/playbooks/tasks/services/service/03-pod.d/rproxy.yml b/playbooks/tasks/services/service/03-pod.d/rproxy.yml new file mode 100644 index 0000000..2bed8a5 --- /dev/null +++ b/playbooks/tasks/services/service/03-pod.d/rproxy.yml @@ -0,0 +1,20 @@ +- block: + - name: Create html directory for letsencrypt + file: + path: "{{ service_home }}/.config/{{ service_user_name }}/html" + state: directory + mode: 0755 + + - name: Generate Diffie Hellman ephemeral parameters + command: openssl dhparam --out /{{ service_home }}/.config/{{ service_user_name}}/dhparam.pem 4096 + args: + creates: "{{ service_home }}/.config/{{ service_user_name }}/dhparam.pem" + register: dhparam + + - name: Record changes + set_fact: + service_changed: true + when: + dhparam is changed + + become_user: "{{ service_user_name }}" diff --git a/playbooks/tasks/services/service/03-pod.d/www.yml b/playbooks/tasks/services/service/03-pod.d/www.yml new file mode 100644 index 0000000..a0474f4 --- /dev/null +++ b/playbooks/tasks/services/service/03-pod.d/www.yml @@ -0,0 +1,28 @@ +- block: + - name: Check if hugo is installed + stat: + path: "/usr/local/bin/hugo" + register: hugo_path + + - name: Install hugo + become_user: root + apt: + deb: https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_extended_0.56.0_Linux-64bit.deb + when: + not hugo_path.stat.exists + + - name: Clone website repository + git: + repo: https://gitlab.wojciechkozlowski.eu/wojtek/wojciechkozlowski.eu.git + dest: "{{ service_home }}/.config/{{ service_user_name }}/wojciechkozlowski.eu" + recursive: yes + register: wojciechkozlowski_eu_git + + - name: Generate static page using hugo + command: + cmd: hugo + chdir: "{{ service_home }}/.config/{{ service_user_name }}/wojciechkozlowski.eu" + when: + wojciechkozlowski_eu_git is changed + + become_user: "{{ service_user_name }}" diff --git a/playbooks/tasks/services/service/03-pod.yml b/playbooks/tasks/services/service/03-pod.yml new file mode 100644 index 0000000..d058f9a --- /dev/null +++ b/playbooks/tasks/services/service/03-pod.yml @@ -0,0 +1,78 @@ +- block: + - name: Create configuration directory for user {{ service_user_name }} + file: + path: "{{ service_home }}/.config" + state: directory + mode: 0755 + + - name: Check if service configuration exists + become: no + delegate_to: localhost + stat: + path: "{{ local_service_home }}/.config/{{ service_user_name }}" + register: local_service_path + + - name: Synchronise service configuration + copy: + src: "{{ local_service_home }}/.config/{{ service_user_name }}" + dest: "{{ service_home }}/.config" + directory_mode: 0755 + mode: 0644 + register: service_synchronise + when: + local_service_path.stat.exists + + - include_tasks: "{{ item }}" + with_first_found: + - files: + - "03-pod.d/{{ service_name }}.yml" + skip: true + + - name: Create systemd directory for user {{ service_user_name }} + file: + path: "{{ service_home }}/.config/systemd" + state: directory + mode: 0755 + + - name: Create systemd service directory for user {{ service_user_name }} + file: + path: "{{ service_home }}/.config/systemd/user" + state: directory + mode: 0755 + + - name: Configure {{ service_user_name }} service + template: + src: "{{ item }}" + dest: /{{ service_home }}/.config/systemd/user/{{ item | basename | regex_replace('\.j2','') }} + mode: 0644 + with_fileglob: + - "{{ local_service_home }}/.config/systemd/user/*.j2" + register: systemd_pod_service_files + + - name: SystemD user daemon reload + systemd: + daemon_reload: true + scope: user + when: + systemd_pod_service_files is changed + + - name: Enable the {{ service_name }} service + systemd: + name: "pod-{{ service_name }}.service" + enabled: yes + state: started + scope: user + register: systemd_pod_service_enable + + - name: Restart the {{ service_name }} service + systemd: + name: "pod-{{ service_name }}.service" + state: restarted + scope: user + when: + (service_synchronise is changed or + service_changed is true or + systemd_pod_service_files is changed) and + systemd_pod_service_enable is not changed + + become_user: "{{ service_user_name }}" diff --git a/playbooks/tasks/vpn/bridge.yml b/playbooks/tasks/vpn/bridge.yml index b2b401d..11f69fe 100644 --- a/playbooks/tasks/vpn/bridge.yml +++ b/playbooks/tasks/vpn/bridge.yml @@ -17,7 +17,12 @@ src: ./filesystem/{{ ansible_hostname }}/etc/network/interfaces.d/br0.j2 dest: /etc/network/interfaces.d/br0 mode: 0644 - validate: bash -c 'if ! diff %s /etc/network/interfaces.d/br0 && ip link show dev br0 ; then ifdown br0 ; fi' + validate: > + bash -c + 'if ! diff %s /etc/network/interfaces.d/br0 && ip link show dev br0 ; + then + ifdown br0 ; + fi' register: br_intf - name: Restart bridge interface diff --git a/playbooks/tasks/vpn/wireguard.yml b/playbooks/tasks/vpn/wireguard.yml index 37aff6d..99a93d5 100644 --- a/playbooks/tasks/vpn/wireguard.yml +++ b/playbooks/tasks/vpn/wireguard.yml @@ -28,7 +28,12 @@ src: ./filesystem/{{ ansible_hostname }}/etc/network/interfaces.d/wg0.j2 dest: /etc/network/interfaces.d/wg0 mode: 0644 - validate: bash -c 'if ! diff %s /etc/network/interfaces.d/wg0 && ip link show dev wg0 ; then ifdown wg0 ; fi' + validate: > + bash -c + 'if ! diff %s /etc/network/interfaces.d/wg0 && ip link show dev wg0 ; + then + ifdown wg0 ; + fi' register: wg_intf - name: Restart WireGuard interface