diff --git a/ansible/files/postgresql_config/postgresql.service b/ansible/files/postgresql_config/postgresql.service index efb52f18e..68c37140b 100644 --- a/ansible/files/postgresql_config/postgresql.service +++ b/ansible/files/postgresql_config/postgresql.service @@ -24,6 +24,7 @@ LimitNOFILE=16384 {% if supabase_internal is defined %} ReadOnlyPaths=/etc InaccessiblePaths=/root -/var/lib/supabase -/var/lib/supabase-admin-agent -/var/cache/supabase-admin-agent -/opt/saltstack -/etc/salt +AppArmorProfile=-sbpostgres {% endif %} [Install] WantedBy=multi-user.target diff --git a/ansible/files/postgresql_config/sbpostgres_apparmor b/ansible/files/postgresql_config/sbpostgres_apparmor new file mode 100644 index 000000000..7ddd63964 --- /dev/null +++ b/ansible/files/postgresql_config/sbpostgres_apparmor @@ -0,0 +1,204 @@ +#include + +# ============================================ +# POSTGRES PROFILE - With Supabase specific restrictions +# ============================================ +profile sbpostgres flags=(attach_disconnected) { + #include + #include + #include + + # Parent binary access to self + /var/lib/postgresql/.nix-profile/bin/postgres mr, + /nix/store/*/bin/.postgres-wrapped mr, + /nix/store/*/bin/.postgres-wrapped ix, + + # Wide open permissions for parent - to be tuned + # some of this is managed via systemd sandboxing already + /** rw, + owner /** m, + / wr, + /nix/store/** m, + /etc r, + /usr/local r, + # lock permission for pgroonga + /data/pgdata/pgroonga.log k, + + # Systemd notification socket (for Type=notify services) + /run/systemd/notify w, + /{,var/}run/systemd/notify w, + + # Allow disconnected paths (for mount namespaces) + @{run}/systemd/notify w, + /run/systemd/notify w, + + # Full network access + network inet stream, + network inet6 stream, + network unix stream, + + # All capabilities + capability, + + # Libraries + /lib/aarch64-linux-gnu/*.so* mr, + /usr/lib/aarch64-linux-gnu/*.so* mr, + /nix/store/*/lib/*.so* mr, + + # safe commands + /usr/bin/true ix, + /usr/bin/false ix, + # kill needed for postgresql to reload itself + /bin/kill ix, + + # When parent executes shell, transition to restricted profile + # This accounts for popen, which postgres uses for any child process + # Px = discrete profile transition (child gets different profile) + /bin/sh Pix -> postgres_shell, + /bin/bash Pix -> postgres_shell, + /bin/dash Pix -> postgres_shell, + /usr/bin/sh Pix -> postgres_shell, + /usr/bin/dash Pix -> postgres_shell, + /nix/store/*/bin/bash Pix -> postgres_shell, + /usr/lib/postgresql/bin/pgsodium_getkey.sh Pix -> postgres_shell, + /usr/bin/cat Pix -> postgres_shell, + /bin/cat Pix -> postgres_shell, + /usr/bin/admin-mgr Pix -> postgres_shell, + /nix/store/*/bin/wal-g-2 Pix -> postgres_shell, + /nix/store/*/bin/pgbackrest Pix -> postgres_shell, + /usr/bin/pgbackrest Pix -> pgbackrest_shell, + /usr/bin/nix Pix -> pgbackrest_shell, + /usr/bin/sudo Pix -> pgbackrest_shell, + + profile postgres_shell { + #include + + /usr/bin/* m, + /bin/* m, + + # Shell binary + /usr/bin/sh mr, + /usr/bin/bash mr, + /usr/bin/dash mr, + /nix/store/*/bin/bash mr, + + # Only allow specific commands to be executed from shell + /usr/bin/gzip ix, + /usr/bin/cat ix, + /usr/bin/pg_dump ix, + /bin/echo ix, + /bin/bash ix, + /bin/cat ix, + # pgbackrest needs nix and sudo + /usr/bin/nix ix, + /usr/bin/sudo ix, + + # backup things + /usr/lib/postgresql/bin/pgsodium_getkey.sh ix, + /usr/bin/admin-mgr ix, + /nix/store/*/bin/.postgres-wrapped ix, + /nix/store/*/bin/wal-g-2 ix, + /nix/store/*/bin/pgbackrest ix, + + # file path permissions + /** r, + /data/wal_fetch_dir/ rw, + /tmp/wal_fetch_dir/ rw, + /var/lib/postgresql/data rw, + /data/pgdata rw, + /data/latest-lsn-checkpoint-v2 rw, + /data/previous-lsn-checkpoint-v2 rw, + /var/lib/postgresql/data/recovery.signal rw, + /var/lib/postgresql/data/standby.signal rw, + /var/lib/pgbackrest rw, + /etc/pgbackrest/conf.d/** rw, + /var/spool/pgbackrest/** rw, + /var/log/pgbackrest/** rw, + /etc/** r, + /usr/local/** r, + + + deny /var/lib/supabase/** rwx, + deny /var/lib/supabase-admin-agent/** rwx, + deny /var/cache/supabase-admin-agent/** rwx, + deny /opt/saltstack/** rwx, + deny /etc/salt/** rwx, + deny /root wr, + deny /home/** wr, + # wal-g needs access to its own home directory + /home/wal-g/* wr, + + # Libraries + /lib/aarch64-linux-gnu/*.so* mr, + /usr/lib/aarch64-linux-gnu/*.so* mr, + /nix/store/*/lib/*.so* mr, + + # full network access + # could further break this up so that only backup + # tools have network access + network, + + # Block everything else + deny /** x, + } + + profile pgbackrest_shell { + #include + + /usr/bin/* m, + /bin/* m, + + # Shell binary + /usr/bin/sh mr, + /usr/bin/bash mr, + /usr/bin/dash mr, + /nix/store/*/bin/bash mr, + + # pgbackrest needs nix and sudo + /usr/bin/nix ix, + /usr/bin/sudo ix, + /bin/bash ix, + + /usr/bin/admin-mgr ix, + /nix/store/*/bin/.postgres-wrapped ix, + /nix/store/*/bin/pgbackrest ix, + + # file path permissions + /** r, + /data/wal_fetch_dir/ rw, + /tmp/wal_fetch_dir/ rw, + /var/lib/postgresql/data rw, + /data/pgdata rw, + /data/latest-lsn-checkpoint-v2 rw, + /data/previous-lsn-checkpoint-v2 rw, + /var/lib/postgresql/data/recovery.signal rw, + /var/lib/postgresql/data/standby.signal rw, + /var/lib/pgbackrest rw, + /etc/pgbackrest/conf.d/** rw, + /var/spool/pgbackrest/** rw, + /var/log/pgbackrest/** rw, + /etc/** r, + /usr/local/** r, + + deny /var/lib/supabase/** rwx, + deny /var/lib/supabase-admin-agent/** rwx, + deny /var/cache/supabase-admin-agent/** rwx, + deny /opt/saltstack/** rwx, + deny /etc/salt/** rwx, + deny /root wr, + deny /home/** wr, + + # Libraries + /lib/aarch64-linux-gnu/*.so* mr, + /usr/lib/aarch64-linux-gnu/*.so* mr, + /nix/store/*/lib/*.so* mr, + + # full network access + # could further break this up so that only backup + # tools have network access + network, + + # Block everything else + deny /** x, + } +} diff --git a/ansible/tasks/setup-postgres.yml b/ansible/tasks/setup-postgres.yml index be6fa0840..558460551 100644 --- a/ansible/tasks/setup-postgres.yml +++ b/ansible/tasks/setup-postgres.yml @@ -286,6 +286,22 @@ when: - (is_psql_oriole or is_psql_17) +- name: copy PG apparmor profile + ansible.builtin.copy: + dest: '/etc/apparmor.d/sbpostgres' + group: 'root' + mode: '0644' + owner: 'root' + src: 'files/postgresql_config/sbpostgres_apparmor' + +- name: parse apparmor sbpostgres profile + ansible.builtin.command: + cmd: '/usr/sbin/apparmor_parser -r /etc/apparmor.d/sbpostgres' + +- name: reload apparmor with sbpostgres profile + ansible.builtin.command: + cmd: '/usr/sbin/aa-enforce sbpostgres' + - name: copy PG and optimizations systemd units ansible.builtin.template: dest: "/etc/systemd/system/{{ systemd_svc_item | basename }}" @@ -376,7 +392,7 @@ dest: '/var/lib/postgresql/.bashrc' line: "{{ lang_item }}" become: true - loop: + loop: - 'export LOCALE_ARCHIVE=/usr/lib/locale/locale-archive' - 'export LANG="en_US.UTF-8"' - 'export LANGUAGE="en_US.UTF-8"' diff --git a/ansible/vars.yml b/ansible/vars.yml index 7c691c3ae..baca1f284 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -10,9 +10,9 @@ postgres_major: # Full version strings for each major version postgres_release: - postgresorioledb-17: "17.6.0.055-orioledb" - postgres17: "17.6.1.098" - postgres15: "15.14.1.098" + postgresorioledb-17: "17.6.0.056-orioledb" + postgres17: "17.6.1.099" + postgres15: "15.14.1.099" # Non Postgres Extensions pgbouncer_release: 1.25.1