From a4d570b77c3e7fd844057fa25d08d1f8f56e4422 Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Tue, 17 Mar 2026 18:11:14 +0100 Subject: [PATCH 1/5] feat: add apparmor profile --- .../postgresql_config/postgresql.service | 1 + .../postgresql_config/sbpostgres_apparmor | 204 ++++++++++++++++++ ansible/tasks/setup-postgres.yml | 14 +- ansible/vars.yml | 6 +- 4 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 ansible/files/postgresql_config/sbpostgres_apparmor diff --git a/ansible/files/postgresql_config/postgresql.service b/ansible/files/postgresql_config/postgresql.service index efb52f18eb..68c37140bd 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 0000000000..7ddd639644 --- /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 be6fa0840c..60842975cf 100644 --- a/ansible/tasks/setup-postgres.yml +++ b/ansible/tasks/setup-postgres.yml @@ -286,6 +286,18 @@ when: - (is_psql_oriole or is_psql_17) +- name: copy PG apparmor profile + ansible.builtin.copy: + dest: '/etc/apparmor.d/sbpostgres' + mode: '0644' + owner: 'root' + group: 'root' + src: 'files/postgresql_config/sbpostgres_apparmor' + +- name: reload apparmor with sbpostgres profile + ansible.builtin.command: + cmd: '/usr/sbin/apparmor_parser -r /etc/apparmor.d/sbpostgres && /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 +388,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 e6a3407f81..b369d3ddad 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.054-orioledb" - postgres17: "17.6.1.097" - postgres15: "15.14.1.097" + postgresorioledb-17: "17.6.0.055-orioledb-apparmor" + postgres17: "17.6.1.098-apparmor" + postgres15: "15.14.1.098-apparmor" # Non Postgres Extensions pgbouncer_release: 1.25.1 From a453045650add9343d4f9f1c4a6423b49b810000 Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Tue, 17 Mar 2026 18:57:35 +0100 Subject: [PATCH 2/5] fix: split commands --- ansible/tasks/setup-postgres.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ansible/tasks/setup-postgres.yml b/ansible/tasks/setup-postgres.yml index 60842975cf..170a329874 100644 --- a/ansible/tasks/setup-postgres.yml +++ b/ansible/tasks/setup-postgres.yml @@ -294,9 +294,13 @@ group: '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/apparmor_parser -r /etc/apparmor.d/sbpostgres && /usr/sbin/aa-enforce sbpostgres' + cmd: '/usr/sbin/aa-enforce sbpostgres' - name: copy PG and optimizations systemd units ansible.builtin.template: From 12d7d969a1ee239f8b06c947c01a0014c99fd1fb Mon Sep 17 00:00:00 2001 From: Douglas J Hunley Date: Wed, 18 Mar 2026 13:21:56 -0400 Subject: [PATCH 3/5] Update ansible/tasks/setup-postgres.yml --- ansible/tasks/setup-postgres.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ansible/tasks/setup-postgres.yml b/ansible/tasks/setup-postgres.yml index 170a329874..87a111c2c8 100644 --- a/ansible/tasks/setup-postgres.yml +++ b/ansible/tasks/setup-postgres.yml @@ -289,9 +289,9 @@ - name: copy PG apparmor profile ansible.builtin.copy: dest: '/etc/apparmor.d/sbpostgres' - mode: '0644' - owner: 'root' group: 'root' + mode: '0644' + owner: 'root' src: 'files/postgresql_config/sbpostgres_apparmor' - name: parse apparmor sbpostgres profile From 41d5a4200cce5fa724a0179ce9304adaa621786a Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Thu, 19 Mar 2026 09:01:20 +0100 Subject: [PATCH 4/5] feat: bump version numbers --- ansible/vars.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ansible/vars.yml b/ansible/vars.yml index b369d3ddad..baca1f2847 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-apparmor" - postgres17: "17.6.1.098-apparmor" - postgres15: "15.14.1.098-apparmor" + 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 From 962c4e99ef3f929744b4b0b28cf1e1ef544eb6a2 Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Thu, 19 Mar 2026 10:13:26 +0100 Subject: [PATCH 5/5] fix: correct indent --- ansible/tasks/setup-postgres.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/tasks/setup-postgres.yml b/ansible/tasks/setup-postgres.yml index 87a111c2c8..5584605513 100644 --- a/ansible/tasks/setup-postgres.yml +++ b/ansible/tasks/setup-postgres.yml @@ -291,7 +291,7 @@ dest: '/etc/apparmor.d/sbpostgres' group: 'root' mode: '0644' - owner: 'root' + owner: 'root' src: 'files/postgresql_config/sbpostgres_apparmor' - name: parse apparmor sbpostgres profile