Skip to content

feat: add the supabase admin agent to the ami build #1679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/nix-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ jobs:
trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI=% cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
- name: Build psql bundle
run: >
nix run "github:Mic92/nix-fast-build?rev=b1dae483ab7d4139a6297e02b6de9e5d30e43d48"
-- --skip-cached --no-nom
--flake ".#checks.$(nix eval --raw --impure --expr 'builtins.currentSystem')"
nix run "github:Mic92/nix-fast-build?rev=b1dae483ab7d4139a6297e02b6de9e5d30e43d48"
-- --skip-cached --no-nom
--flake ".#checks.$(nix eval --raw --impure --expr 'builtins.currentSystem')"
env:
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ env.AWS_SESSION_TOKEN }}

run-testinfra:
needs: build-run-image
if: ${{ success() }}
uses: ./.github/workflows/testinfra-ami-build.yml

run-tests:
needs: build-run-image
if: ${{ success() }}
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/testinfra-ami-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
ubuntu_release: focal
ubuntu_version: 20.04
mcpu: neoverse-n1
runs-on: ${{ matrix.runner }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 150
permissions:
contents: write
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
echo 'postgres-version = "'$PG_VERSION'"' > common-nix.vars.pkr.hcl
# Ensure there's a newline at the end of the file
echo "" >> common-nix.vars.pkr.hcl

- name: Build AMI stage 1
run: |
packer init amazon-arm64-nix.pkr.hcl
Expand All @@ -84,7 +84,7 @@ jobs:
run: |
packer init stage2-nix-psql.pkr.hcl
GIT_SHA=${{github.sha}}
packer build -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${GITHUB_RUN_ID}" -var "postgres_major_version=${POSTGRES_MAJOR_VERSION}" -var-file="development-arm.vars.pkr.hcl" -var-file="common-nix.vars.pkr.hcl" -var "postgres-version=${{ steps.random.outputs.random_string }}" -var "region=ap-southeast-1" -var 'ami_regions=["ap-southeast-1"]' -var "force-deregister=true" -var "git_sha=${GITHUB_SHA}" stage2-nix-psql.pkr.hcl
packer build -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${GITHUB_RUN_ID}" -var "postgres_major_version=${POSTGRES_MAJOR_VERSION}" -var-file="development-arm.vars.pkr.hcl" -var-file="common-nix.vars.pkr.hcl" -var "postgres-version=${{ steps.random.outputs.random_string }}" -var "region=ap-southeast-1" -var 'ami_regions=["ap-southeast-1"]' -var "force-deregister=true" -var "git_sha=${GITHUB_SHA}" stage2-nix-psql.pkr.hcl

- name: Run tests
timeout-minutes: 10
Expand All @@ -93,8 +93,8 @@ jobs:
run: |
# TODO: use poetry for pkg mgmt
pip3 install boto3 boto3-stubs[essential] docker ec2instanceconnectcli pytest pytest-testinfra[paramiko,docker] requests
pytest -vv -s testinfra/test_ami_nix.py
pytest -vv -s testinfra/test_ami_nix.py

- name: Cleanup resources on build cancellation
if: ${{ cancelled() }}
run: |
Expand All @@ -111,7 +111,7 @@ jobs:
# Define AMI name patterns
STAGE1_AMI_NAME="supabase-postgres-ci-ami-test-stage-1"
STAGE2_AMI_NAME="${{ steps.random.outputs.random_string }}"

# Function to deregister AMIs by name pattern
deregister_ami_by_name() {
local ami_name_pattern=$1
Expand All @@ -121,7 +121,7 @@ jobs:
aws ec2 deregister-image --region ap-southeast-1 --image-id $ami_id
done
}

# Deregister AMIs
deregister_ami_by_name "$STAGE1_AMI_NAME"
deregister_ami_by_name "$STAGE2_AMI_NAME"
10 changes: 10 additions & 0 deletions ansible/files/permission_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,17 @@
"systemd-coredump": [
{"groupname": "systemd-coredump", "username": "systemd-coredump"}
],
"supabase-admin-agent": [
{"groupname": "supabase-admin-agent", "username": "supabase-admin-agent"},
{"groupname": "admin", "username": "supabase-admin-agent"},
{"groupname": "salt", "username": "supabase-admin-agent"},
],
}

# postgresql.service is expected to mount /etc as read-only
expected_mount = "/etc ro"


# This program depends on osquery being installed on the system
# Function to run osquery
def run_osquery(query):
Expand Down Expand Up @@ -154,6 +160,7 @@ def check_nixbld_users():

print("All nixbld users are in the 'nixbld' group.")


def check_postgresql_mount():
# processes table has the nix .postgres-wrapped path as the
# binary path, rather than /usr/lib/postgresql/bin/postgres which
Expand Down Expand Up @@ -182,6 +189,7 @@ def check_postgresql_mount():

print("postgresql.service mounts /etc as read-only.")


def main():
parser = argparse.ArgumentParser(
prog="Supabase Postgres Artifact Permissions Checker",
Expand Down Expand Up @@ -234,6 +242,7 @@ def main():
"postgrest",
"tcpdump",
"systemd-coredump",
"supabase-admin-agent",
]
if not qemu_artifact:
usernames.append("ec2-instance-connect")
Expand All @@ -251,5 +260,6 @@ def main():
# Check if postgresql.service is using a read-only mount for /etc
check_postgresql_mount()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
%supabase-admin-agent ALL= NOPASSWD: /usr/bin/salt-call
%supabase-admin-agent ALL= NOPASSWD: /usr/bin/gpg --homedir {{ gpgdir }} --import, /usr/bin/gpg --homedir {{ gpgdir }} --list-secret-keys *
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[Unit]
Description=Configuration management via supabase-admin-agent salt
After=network.target

[Service]
Type=oneshot
ExecStart=/opt/supabase-admin-agent/supabase-admin-agent --config /opt/supabase-admin-agent/config.yaml salt --apply --store-result
User=supabase-admin-agent
Group=supabase-admin-agent
StandardOutput=journal
StandardError=journal
StateDirectory=supabase-admin-agent
CacheDirectory=supabase-admin-agent

# Security hardening
PrivateTmp=true

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Run Supabase supabase-admin-agent salt on a schedule
Requires=supabase-admin-agent_salt.service

[Timer]
OnCalendar=*:0/10
# Random delay up to {{ splay }} seconds splay
RandomizedDelaySec={{ splay }}
AccuracySec=1s
Persistent=true

[Install]
WantedBy=timers.target
87 changes: 87 additions & 0 deletions ansible/tasks/internal/supabase-admin-agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
- name: supabase-admin-agent - system group
group:
name: supabase-admin-agent
system: yes

- name: supabase-admin-agent - system user
user:
name: supabase-admin-agent
group: supabase-admin-agent
groups: admin,salt
append: yes
system: yes
shell: /bin/sh

- name: supabase-admin-agent - config dir
file:
path: /opt/supabase-admin-agent
owner: supabase-admin-agent
state: directory

- name: supabase-admin-agent - gpg dir
file:
path: /etc/salt/gpgkeys
owner: root
group: salt
state: directory

- name: give supabase-admin-agent user permissions
copy:
src: files/supabase_admin_agent_config/supabase-admin-agent.sudoers.conf
dest: /etc/sudoers.d/supabase-admin-agent
mode: "0644"

- name: Setting arch (x86)
set_fact:
arch: "x86"
when: platform == "amd64"

- name: Setting arch (arm)
set_fact:
arch: "arm64"
when: platform == "arm64"

- name: Download supabase-admin-agent archive
get_url:
url: "https://supabase-public-artifacts-bucket.s3.amazonaws.com/supabase-admin-agent/v{{ supabase_admin_agent_release }}/supabase-admin-agent-{{ supabase_admin_agent_release }}-linux-{{ arch }}.tar.gz"
dest: "/tmp/supabase-admin-agent.tar.gz"
timeout: 90

- name: supabase-admin-agent - unpack archive in /opt
unarchive:
remote_src: yes
src: /tmp/supabase-admin-agent.tar.gz
dest: /opt/supabase-admin-agent/
owner: supabase-admin-agent
extra_opts:
- --strip-components=1

- name: supabase-admin-agent - create symlink
ansible.builtin.file:
path: /opt/supabase-admin-agent/supabase-admin-agent
src: "/opt/supabase-admin-agent/supabase-admin-agent-linux-{{ arch }}"
state: link
owner: supabase-admin-agent
mode: "0755"
force: yes

- name: supabase-admin-agent - create salt systemd timer file
copy:
src: files/supabase_admin_agent_config/supabase-admin-agent_salt.timer
dest: /etc/systemd/system/supabase-admin-agent_salt.timer

- name: supabase-admin-agent - create salt service file
copy:
src: files/supabase_admin_agent_config/supabase-admin-agent_salt.service
dest: /etc/systemd/system/supabase-admin-agent_salt.service

- name: supabase-admin-agent - reload systemd
systemd:
daemon_reload: yes

# Initially ensure supabase-admin-agent is installed but not started
- name: supabase-admin-agent - DISABLE service
systemd:
name: supabase-admin-agent_salt
enabled: no
state: stopped
17 changes: 11 additions & 6 deletions ansible/tasks/setup-supabase-internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@
aws configure set default.s3.use_dualstack_endpoint true
- name: install Vector for logging
become: yes
become: true
apt:
deb: "{{ vector_x86_deb }}"
when: platform == "amd64"

- name: install Vector for logging
become: yes
become: true
apt:
deb: "{{ vector_arm_deb }}"
when: platform == "arm64"

- name: add Vector to postgres group
become: yes
become: true
shell:
cmd: |
usermod -a -G postgres vector
Expand All @@ -72,21 +72,21 @@
daemon_reload: yes

- name: Create checkpoints dir
become: yes
become: true
file:
path: /var/lib/vector
state: directory
owner: vector

- name: Include file for generated optimizations in postgresql.conf
become: yes
become: true
replace:
path: /etc/postgresql/postgresql.conf
regexp: "#include = '/etc/postgresql-custom/generated-optimizations.conf'"
replace: "include = '/etc/postgresql-custom/generated-optimizations.conf'"

- name: Include file for custom overrides in postgresql.conf
become: yes
become: true
replace:
path: /etc/postgresql/postgresql.conf
regexp: "#include = '/etc/postgresql-custom/custom-overrides.conf'"
Expand Down Expand Up @@ -115,5 +115,10 @@
tags:
- aws-only

- name: Install supabase-admin-agent
import_tasks: internal/supabase-admin-agent.yml
tags:
- aws-only

- name: Envoy - use lds.supabase.yaml for /etc/envoy/lds.yaml
command: mv /etc/envoy/lds.supabase.yaml /etc/envoy/lds.yaml
7 changes: 4 additions & 3 deletions ansible/vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ postgres_major:

# Full version strings for each major version
postgres_release:
postgresorioledb-17: "17.0.1.098-orioledb"
postgres17: "17.4.1.048"
postgres15: "15.8.1.105"
postgresorioledb-17: "17.0.1.099-orioledb"
postgres17: "17.4.1.049"
postgres15: "15.8.1.106"

# Non Postgres Extensions
pgbouncer_release: "1.19.0"
Expand Down Expand Up @@ -54,6 +54,7 @@ postgres_exporter_release_checksum:

adminapi_release: 0.84.1
adminmgr_release: 0.25.1
supabase_admin_agent_release: 1.4.36

vector_x86_deb: "https://packages.timber.io/vector/0.22.3/vector_0.22.3-1_amd64.deb"
vector_arm_deb: "https://packages.timber.io/vector/0.22.3/vector_0.22.3-1_arm64.deb"