Add secure postgres deployment
This commit is contained in:
parent
2b1518a5c3
commit
cfb228cada
15 changed files with 115 additions and 26 deletions
|
|
@ -15,13 +15,14 @@
|
||||||
- role: basic-intalls
|
- role: basic-intalls
|
||||||
- role: user
|
- role: user
|
||||||
- role: cloudflare-ddns
|
- role: cloudflare-ddns
|
||||||
|
- role: cloudflared
|
||||||
- role: nginx
|
- role: nginx
|
||||||
- role: actual
|
- role: actual
|
||||||
- role: changedetection
|
- role: changedetection
|
||||||
- role: pi-hole
|
- role: pi-hole
|
||||||
- role: monitoring
|
- role: monitoring
|
||||||
|
- role: postgres
|
||||||
- role: wedding
|
- role: wedding
|
||||||
- role: cloudflared
|
|
||||||
vars:
|
vars:
|
||||||
# devsec.hardening.ssh_hardening vars:
|
# devsec.hardening.ssh_hardening vars:
|
||||||
ssh_client_port: 22 # Default, but duplicated here for documentation purpose. Not changed because its only accessible via LAN.
|
ssh_client_port: 22 # Default, but duplicated here for documentation purpose. Not changed because its only accessible via LAN.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
podman_container_tag: "{{ actual_version }}"
|
podman_container_tag: "{{ actual_version }}"
|
||||||
podman_container_publish:
|
podman_container_publish:
|
||||||
- 127.0.0.1:5006:5006
|
- 127.0.0.1:5006:5006
|
||||||
podman_container_volumes:
|
podman_simple_container_volumes:
|
||||||
- name: actual_data
|
- name: actual_data
|
||||||
mnt: /data
|
mnt: /data
|
||||||
- name: Include simple-reverse-proxy role
|
- name: Include simple-reverse-proxy role
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
podman_container_tag: "{{ changedetection_version }}"
|
podman_container_tag: "{{ changedetection_version }}"
|
||||||
podman_container_publish:
|
podman_container_publish:
|
||||||
- 127.0.0.1:5000:5000
|
- 127.0.0.1:5000:5000
|
||||||
podman_container_volumes:
|
podman_simple_container_volumes:
|
||||||
- name: changedetection_data
|
- name: changedetection_data
|
||||||
mnt: /datastore
|
mnt: /datastore
|
||||||
- name: Include simple-reverse-proxy role
|
- name: Include simple-reverse-proxy role
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
GF_INSTALL_PLUGINS: "grafana-clock-panel 2.1.7"
|
GF_INSTALL_PLUGINS: "grafana-clock-panel 2.1.7"
|
||||||
podman_container_publish:
|
podman_container_publish:
|
||||||
- 127.0.0.1:3000:3000
|
- 127.0.0.1:3000:3000
|
||||||
podman_container_volumes:
|
podman_simple_container_volumes:
|
||||||
- name: grafana_storage
|
- name: grafana_storage
|
||||||
mnt: /var/lib/grafana
|
mnt: /var/lib/grafana
|
||||||
- name: Include simple-reverse-proxy role - Grafana
|
- name: Include simple-reverse-proxy role - Grafana
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
# Cloudflare API token used by Certbot
|
# Cloudflare API token used by Certbot
|
||||||
dns_cloudflare_api_token = {{ dns_cloudflare_api_token }}
|
dns_cloudflare_api_token = {{ dns_cloudflare_token }}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
|
||||||
35613135623165306639373939396435656431326134336466636666393637333532623036303831
|
|
||||||
6534646334633731313838323138303261663536376330640a376538653563353365336634346338
|
|
||||||
34663031643265623838396239383164303865346332366361313839386533363530336361373930
|
|
||||||
6438313861353563630a343738383365656531313137613361323636653635393232343738633433
|
|
||||||
63356634323264623134313565386362663131313963373433306636383661373930323262353663
|
|
||||||
64393433393639346166666433396363313465373032343239633939343830303465633564353130
|
|
||||||
37333437643064346233633863346632393266633435396433396563653737386233346231303061
|
|
||||||
37623138386233303764
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
- 127.0.0.1:5053:53/tcp
|
- 127.0.0.1:5053:53/tcp
|
||||||
- 127.0.0.1:5053:53/udp
|
- 127.0.0.1:5053:53/udp
|
||||||
- 127.0.0.1:8080:80
|
- 127.0.0.1:8080:80
|
||||||
podman_container_volumes:
|
podman_simple_container_volumes:
|
||||||
- name: etc-pihole
|
- name: etc-pihole
|
||||||
mnt: /etc/pihole
|
mnt: /etc/pihole
|
||||||
- name: etc-dnsmasq.d
|
- name: etc-dnsmasq.d
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
path: "/home/{{ container_user }}/{{ item.name }}"
|
path: "/home/{{ container_user }}/{{ item.name }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: '0700'
|
mode: '0700'
|
||||||
loop: "{{ podman_container_volumes }}"
|
loop: "{{ podman_simple_container_volumes }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.name }}"
|
label: "{{ item.name }}"
|
||||||
index_var: index
|
index_var: index
|
||||||
|
|
@ -54,23 +54,21 @@
|
||||||
notify: Reload systemd (daemon-reload)
|
notify: Reload systemd (daemon-reload)
|
||||||
- name: Flush handlers
|
- name: Flush handlers
|
||||||
ansible.builtin.meta: flush_handlers
|
ansible.builtin.meta: flush_handlers
|
||||||
- name: Define empty volume array
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
volumes: []
|
|
||||||
- name: Map volumes to Podman accepted list
|
- name: Map volumes to Podman accepted list
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
volumes: "{{ volumes + ['/home/' + container_user + '/' + item.name + ':' + item.mnt] }}"
|
podman_container_volumes: "{{ podman_container_volumes + ['/home/' + container_user + '/' + item.name + ':' + item.mnt] }}"
|
||||||
with_items: "{{ podman_container_volumes }}"
|
with_items: "{{ podman_simple_container_volumes }}"
|
||||||
- name: Start the container
|
- name: Start the container
|
||||||
containers.podman.podman_container:
|
containers.podman.podman_container:
|
||||||
name: "{{ podman_container_name }}"
|
name: "{{ podman_container_name }}"
|
||||||
image: "{{ podman_container_image }}:{{ podman_container_tag }}"
|
image: "{{ podman_container_image }}:{{ podman_container_tag }}"
|
||||||
restart_policy: always
|
restart_policy: always
|
||||||
user: root # Still isolated from host system 👍
|
user: root # Still isolated from host system 👍
|
||||||
|
command: "{{ podman_container_command }}"
|
||||||
hostname: "{{ ansible_facts['hostname'] }}"
|
hostname: "{{ ansible_facts['hostname'] }}"
|
||||||
publish: "{{ podman_container_publish }}"
|
publish: "{{ podman_container_publish }}"
|
||||||
env: "{{ podman_container_env }}"
|
env: "{{ podman_container_env }}"
|
||||||
volumes: "{{ volumes }}"
|
volumes: "{{ podman_container_volumes }}"
|
||||||
state: stopped
|
state: stopped
|
||||||
# For more information on the systemd startup service, see: https://linuxhandbook.com/autostart-podman-containers/
|
# For more information on the systemd startup service, see: https://linuxhandbook.com/autostart-podman-containers/
|
||||||
generate_systemd:
|
generate_systemd:
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
---
|
---
|
||||||
podman_container_env: {}
|
podman_container_env: {}
|
||||||
|
podman_container_volumes: []
|
||||||
|
podman_container_command: []
|
||||||
|
|
|
||||||
30
roles/postgres/files/ensure_certificate_setup.sh
Normal file
30
roles/postgres/files/ensure_certificate_setup.sh
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Running as $(whoami)..."
|
||||||
|
|
||||||
|
target_user='postgres'
|
||||||
|
# This user shouldn't be mapped to postgres on the host but rather to postgres on the container.
|
||||||
|
# This user has host uid: 558821 (in container it's uid: 70). This number is resolved by getting the start
|
||||||
|
# of the subuid range for this user and then than adding 70 (-1) to it (since we know that that is the uid
|
||||||
|
# of the postgres user within the container).
|
||||||
|
target_path_subuid_start="$(su $target_user -c 'grep $USER /etc/subuid | cut -d ":" -f 2')"
|
||||||
|
target_host_postgres_id=$(($target_path_subuid_start + 70 - 1))
|
||||||
|
|
||||||
|
certsPath="/home/$target_user/certs"
|
||||||
|
|
||||||
|
if [[ ! -e "$certsPath" ]]; then
|
||||||
|
echo "Certs directory doesn't exist, creating certs directory: $certsPath..."
|
||||||
|
mkdir "$certsPath"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying certificates..."
|
||||||
|
cert_files='/etc/letsencrypt/live/postgres.kleinendorst.info/fullchain.pem /etc/letsencrypt/live/postgres.kleinendorst.info/privkey.pem'
|
||||||
|
for srcPath in $cert_files; do
|
||||||
|
echo "Copying: $srcPath to $certsPath..."
|
||||||
|
cp -L "$srcPath" "$certsPath"
|
||||||
|
|
||||||
|
newFileName="$certsPath/$(basename $srcPath)"
|
||||||
|
echo "Setting permissions for: $newFileName to uid: $target_host_postgres_id..."
|
||||||
|
|
||||||
|
chown "$target_host_postgres_id:$target_host_postgres_id" "$newFileName"
|
||||||
|
chmod 0600 "$newFileName"
|
||||||
|
done
|
||||||
53
roles/postgres/tasks/main.yml
Normal file
53
roles/postgres/tasks/main.yml
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
- name: Include user role
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: user
|
||||||
|
vars:
|
||||||
|
user_username: "{{ postgres_unix_username }}"
|
||||||
|
user_password: "{{ postgres_unix_password }}"
|
||||||
|
- name: Install ensure_certificate_setup.sh
|
||||||
|
become: true
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ensure_certificate_setup.sh
|
||||||
|
dest: "/root/.bin/"
|
||||||
|
mode: '0700'
|
||||||
|
owner: root
|
||||||
|
- name: Create certificates for PostgreSQL (postgres.kleinendorst.info)
|
||||||
|
become: true
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: >-
|
||||||
|
/snap/bin/certbot certonly
|
||||||
|
--dns-cloudflare
|
||||||
|
--dns-cloudflare-propagation-seconds 120
|
||||||
|
--dns-cloudflare-credentials '/root/.secrets/certbot/cloudflare.ini'
|
||||||
|
--deploy-hook '/root/.bin/ensure_certificate_setup.sh'
|
||||||
|
--agree-tos -m {{ administration_email }}
|
||||||
|
-d postgres.kleinendorst.info
|
||||||
|
creates: "/etc/letsencrypt/live/postgres.kleinendorst.info"
|
||||||
|
- name: Create the postgres container
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: podman-container
|
||||||
|
apply:
|
||||||
|
become: true
|
||||||
|
become_user: "{{ postgres_unix_username }}"
|
||||||
|
vars:
|
||||||
|
podman_container_name: postgres
|
||||||
|
podman_container_image: docker.io/postgres
|
||||||
|
podman_container_tag: "{{ postgres_version }}"
|
||||||
|
podman_container_publish:
|
||||||
|
- 0.0.0.0:5432:5432
|
||||||
|
podman_container_volumes:
|
||||||
|
- "/home/{{ postgres_unix_username }}/certs/fullchain.pem:/var/lib/postgresql/fullchain.pem:ro"
|
||||||
|
- "/home/{{ postgres_unix_username }}/certs/privkey.pem:/var/lib/postgresql/privkey.pem:ro"
|
||||||
|
podman_simple_container_volumes:
|
||||||
|
- name: postgres_data
|
||||||
|
mnt: /var/lib/postgresql/data
|
||||||
|
podman_container_command:
|
||||||
|
- -c
|
||||||
|
- ssl=on
|
||||||
|
- -c
|
||||||
|
- ssl_cert_file=/var/lib/postgresql/fullchain.pem
|
||||||
|
- -c
|
||||||
|
- ssl_key_file=/var/lib/postgresql/privkey.pem
|
||||||
|
podman_container_env:
|
||||||
|
POSTGRES_PASSWORD: "{{ postgres_password }}"
|
||||||
3
roles/postgres/vars/main/defaults.yml
Normal file
3
roles/postgres/vars/main/defaults.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
postgres_unix_username: postgres
|
||||||
|
postgres_version: 17-alpine
|
||||||
11
roles/postgres/vars/main/vault.yml
Normal file
11
roles/postgres/vars/main/vault.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
33656630396365636165633936316636323163303463643436303933636263326666313933366662
|
||||||
|
3437333064663362666632383137323839326431333966350a653633376662626134333730313430
|
||||||
|
33646337396530616230313062313737343639666234353262356436636364336463643430303438
|
||||||
|
6639346363663231360a386663363632316361613238666465626238666436303561653265666431
|
||||||
|
33316538613366316663303666306263386433373838343061363865313833303037653330343631
|
||||||
|
61653438333361323234666662373965636464346132613339623436343262316636346363643830
|
||||||
|
61626238616561663139323530373933623938633666373637376636353134303638613165643866
|
||||||
|
34343036653365303630643333326165623334353038653961313731336538633830363732616137
|
||||||
|
35343762613738383536653833646263326638663034326638323639343365633863343238356264
|
||||||
|
3239656338663861343337333866306636353764363433636437
|
||||||
|
|
@ -25,14 +25,14 @@
|
||||||
podman_container_tag: "{{ wedding_version }}"
|
podman_container_tag: "{{ wedding_version }}"
|
||||||
podman_container_publish:
|
podman_container_publish:
|
||||||
- 127.0.0.1:3001:3000
|
- 127.0.0.1:3001:3000
|
||||||
podman_container_volumes: []
|
podman_simple_container_volumes: []
|
||||||
podman_container_env:
|
podman_container_env:
|
||||||
DATABASE_HOST: 'localhost' # TODO: Needs to be fixed later...
|
DATABASE_HOST: 'postgres.kleinendorst.info'
|
||||||
DATABASE_PORT: 5432
|
DATABASE_PORT: 5432
|
||||||
DATABASE_DBNAME: wedding
|
DATABASE_DBNAME: wedding
|
||||||
DATABASE_USER: "{{ postgres.user }}"
|
DATABASE_USER: "{{ postgres.user }}"
|
||||||
DATABASE_PASSWORD: "{{ postgres.password }}"
|
DATABASE_PASSWORD: "{{ postgres.password }}"
|
||||||
SESSION_SECRET: "{{ wedding_env.secret }}"
|
SESSION_SECRET: "{{ wedding_env.secret }}"
|
||||||
# NODE_ENV: production # TODO: Enable when ready for secure cookie testing...
|
NODE_ENV: production
|
||||||
WEDDING_FULL_ACCESS_CODE: "{{ wedding_env.full_access_code }}"
|
WEDDING_FULL_ACCESS_CODE: "{{ wedding_env.full_access_code }}"
|
||||||
WEDDING_NIGHT_ACCESS_CODE: "{{ wedding_env.night_access_code }}"
|
WEDDING_NIGHT_ACCESS_CODE: "{{ wedding_env.night_access_code }}"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
---
|
---
|
||||||
wedding_username: wedding
|
wedding_username: wedding
|
||||||
wedding_version: 0.0.3
|
wedding_version: 0.0.5
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue