Skip to content

feat: Install gandalf, salt-wrapper for infra #1657

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 19 commits into from
Jun 25, 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
2 changes: 2 additions & 0 deletions ansible/files/gandalf_config/gandalf.sudoers.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
%gandalf ALL= NOPASSWD: /usr/bin/salt-call
%gandalf ALL= NOPASSWD: /usr/bin/gpg --homedir /etc/salt/gpgkeys --import, /usr/bin/gpg --homedir /etc/salt/gpgkeys --list-secret-keys *
19 changes: 19 additions & 0 deletions ansible/files/gandalf_config/gandalf_salt.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[Unit]
Description=Configuration management via gandalf salt
After=network.target

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

# Security hardening
PrivateTmp=true

[Install]
WantedBy=multi-user.target
13 changes: 13 additions & 0 deletions ansible/files/gandalf_config/gandalf_salt.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Run Supabase gandalf salt on a schedule
Requires=gandalf_salt.service

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

[Install]
WantedBy=timers.target
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"}
],
"gandalf": [
{"groupname": "gandalf", "username": "gandalf"},
{"groupname": "admin", "username": "gandalf"},
{"groupname": "salt", "username": "gandalf"},
],
}

# 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",
"gandalf",
]
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()
18 changes: 18 additions & 0 deletions ansible/manifest-playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@
shell: |
cd /tmp && tar -cJf admin-mgr-{{ adminmgr_release }}-arm64.tar.xz admin-mgr

- name: Download gandalf archive
get_url:
url: "https://supabase-public-artifacts-bucket.s3.amazonaws.com/gandalf/v{{ gandalf_release }}/gandalf_{{ gandalf_release }}_linux_arm64.tar.gz"
dest: "/tmp/gandalf.tar.gz"
timeout: 90

- name: gandalf - unpack archive in /tmp
unarchive:
remote_src: yes
src: /tmp/gandalf.tar.gz
dest: /tmp

- name: gandalf - pack archive
shell: |
cd /tmp && tar -cJf gandalf-{{ gandalf_release }}-arm64.tar.xz gandalf

- name: upload archives
shell: |
aws s3 cp /tmp/{{ item.file }} s3://{{ internal_artifacts_bucket }}/upgrades/{{ item.service }}/{{ item.file }}
Expand All @@ -73,3 +89,5 @@
file: supabase-admin-api-{{ adminapi_release }}-arm64.tar.xz
- service: admin-mgr
file: admin-mgr-{{ adminmgr_release }}-arm64.tar.xz
- service: gandalf
file: gandalf-{{ gandalf_release }}-arm64.tar.xz
87 changes: 87 additions & 0 deletions ansible/tasks/internal/gandalf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
- name: gandalf - system group
group:
name: gandalf
system: yes

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

- name: gandalf - config dir
file:
path: /opt/gandalf
owner: gandalf
state: directory

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

- name: give gandalf user permissions
copy:
src: files/gandalf_config/gandalf.sudoers.conf
dest: /etc/sudoers.d/gandalf
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 gandalf archive
get_url:
url: "https://supabase-public-artifacts-bucket.s3.amazonaws.com/gandalf/v{{ gandalf_release }}/gandalf-{{ gandalf_release }}-linux-{{ arch }}.tar.gz"
dest: "/tmp/gandalf.tar.gz"
timeout: 90

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

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

- name: gandalf - create salt systemd timer file
copy:
src: files/gandalf_config/gandalf_salt.timer
dest: /etc/systemd/system/gandalf_salt.timer

- name: gandalf - create salt service file
copy:
src: files/gandalf_config/gandalf_salt.service
dest: /etc/systemd/system/gandalf_salt.service

- name: gandalf - reload systemd
systemd:
daemon_reload: yes

# Initially ensure gandalf is installed but not started
- name: gandalf - DISABLE service
systemd:
name: gandalf_salt
enabled: no
state: stopped
5 changes: 5 additions & 0 deletions ansible/tasks/setup-supabase-internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,10 @@
tags:
- aws-only

- name: Install gandalf
import_tasks: internal/gandalf.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
8 changes: 5 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.095-orioledb"
postgres17: "17.4.1.45"
postgres15: "15.8.1.102"
postgresorioledb-17: "17.0.1.096-orioledb"
postgres17: "17.4.1.046"
postgres15: "15.8.1.103"

# Non Postgres Extensions
pgbouncer_release: "1.19.0"
Expand Down Expand Up @@ -57,3 +57,5 @@ adminmgr_release: 0.25.1

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"

gandalf_release: 1.4.30