Skip to content

Commit 8ab3a59

Browse files
authored
Merge branch 'develop' into INDATA-253
2 parents 1a25504 + 0155526 commit 8ab3a59

File tree

8 files changed

+103
-71
lines changed

8 files changed

+103
-71
lines changed

.github/actions/nix-install-ephemeral/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ runs:
4444
substituters = https://cache.nixos.org https://nix-postgres-artifacts.s3.amazonaws.com
4545
trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
4646
${{ inputs.push-to-cache == 'true' && 'post-build-hook = /etc/nix/upload-to-cache.sh' || '' }}
47+
max-jobs = 8

.github/workflows/testinfra-ami-build.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,18 @@ jobs:
109109
echo "" >> common-nix.vars.pkr.hcl
110110
111111
- name: Build AMI stage 1
112+
env:
113+
AWS_MAX_ATTEMPTS: 10
114+
AWS_RETRY_MODE: adaptive
112115
run: |
113116
GIT_SHA=${{github.sha}}
114117
nix run github:supabase/postgres/${GIT_SHA}#packer -- init amazon-arm64-nix.pkr.hcl
115118
nix run github:supabase/postgres/${GIT_SHA}#packer -- build -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${EXECUTION_ID}" -var-file="development-arm.vars.pkr.hcl" -var-file="common-nix.vars.pkr.hcl" -var "ansible_arguments=" -var "postgres-version=${{ steps.random.outputs.random_string }}" -var "region=ap-southeast-1" -var 'ami_regions=["ap-southeast-1"]' -var "force-deregister=true" -var "ansible_arguments=-e postgresql_major=${POSTGRES_MAJOR_VERSION}" amazon-arm64-nix.pkr.hcl
116119
117120
- name: Build AMI stage 2
121+
env:
122+
AWS_MAX_ATTEMPTS: 10
123+
AWS_RETRY_MODE: adaptive
118124
run: |
119125
GIT_SHA=${{github.sha}}
120126
nix run github:supabase/postgres/${GIT_SHA}#packer -- init stage2-nix-psql.pkr.hcl

amazon-arm64-nix.pkr.hcl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ source "amazon-ebssurrogate" "source" {
115115
#secret_key = "${var.aws_secret_key}"
116116
force_deregister = var.force-deregister
117117

118+
# Increase timeout for instance stop operations to handle large instances
119+
aws_polling {
120+
delay_seconds = 15
121+
max_attempts = 120 # 120 * 15s = 30 minutes max wait
122+
}
123+
118124
# Use latest official ubuntu noble ami owned by Canonical.
119125
source_ami_filter {
120126
filters = {

ansible/files/permission_check.py

Lines changed: 72 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import subprocess
2-
import json
31
import sys
42
import argparse
53
import os
64
import stat
5+
import pwd
6+
import grp
77

88

99
# Expected groups for each user
@@ -159,21 +159,25 @@
159159
}
160160

161161

162-
# This program depends on osquery being installed on the system
163-
# Function to run osquery
164-
def run_osquery(query):
165-
process = subprocess.Popen(
166-
["osqueryi", "--json", query], stdout=subprocess.PIPE, stderr=subprocess.PIPE
167-
)
168-
output, error = process.communicate()
169-
return output.decode("utf-8")
170-
171-
172-
def parse_json(json_str):
162+
def get_user_groups(username):
163+
"""Get all groups that a user belongs to using Python's pwd and grp modules."""
173164
try:
174-
return json.loads(json_str)
175-
except json.JSONDecodeError as e:
176-
print("Error decoding JSON:", e)
165+
user_info = pwd.getpwnam(username)
166+
user_uid = user_info.pw_uid
167+
user_gid = user_info.pw_gid
168+
169+
# Get all groups
170+
groups = []
171+
for group in grp.getgrall():
172+
# Check if user is in the group (either as primary group or in member list)
173+
if user_gid == group.gr_gid or username in group.gr_mem:
174+
groups.append({"username": username, "groupname": group.gr_name})
175+
176+
# Sort by groupname to match expected behavior
177+
groups.sort(key=lambda x: x["groupname"])
178+
return groups
179+
except KeyError:
180+
print(f"User '{username}' not found")
177181
sys.exit(1)
178182

179183

@@ -195,43 +199,60 @@ def compare_results(username, query_result):
195199

196200

197201
def check_nixbld_users():
198-
query = """
199-
SELECT u.username, g.groupname
200-
FROM users u
201-
JOIN user_groups ug ON u.uid = ug.uid
202-
JOIN groups g ON ug.gid = g.gid
203-
WHERE u.username LIKE 'nixbld%';
204-
"""
205-
query_result = run_osquery(query)
206-
parsed_result = parse_json(query_result)
207-
208-
for user in parsed_result:
209-
if user["groupname"] != "nixbld":
210-
print(
211-
f"User '{user['username']}' is in group '{user['groupname']}' instead of 'nixbld'."
212-
)
213-
sys.exit(1)
202+
"""Check that all nixbld users are only in the nixbld group."""
203+
# Get all users that match the pattern nixbld*
204+
nixbld_users = []
205+
for user in pwd.getpwall():
206+
if user.pw_name.startswith("nixbld"):
207+
nixbld_users.append(user.pw_name)
208+
209+
if not nixbld_users:
210+
print("No nixbld users found")
211+
return
212+
213+
# Check each nixbld user's groups
214+
for username in nixbld_users:
215+
groups = get_user_groups(username)
216+
for user_group in groups:
217+
if user_group["groupname"] != "nixbld":
218+
print(
219+
f"User '{username}' is in group '{user_group['groupname']}' instead of 'nixbld'."
220+
)
221+
sys.exit(1)
214222

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

217225

218226
def check_postgresql_mount():
219-
# processes table has the nix .postgres-wrapped path as the
220-
# binary path, rather than /usr/lib/postgresql/bin/postgres which
221-
# is a symlink to /var/lib/postgresql/.nix-profile/bin/postgres, a script
222-
# that ultimately calls /nix/store/...-postgresql-and-plugins-15.8/bin/.postgres-wrapped
223-
query = """
224-
SELECT pid
225-
FROM processes
226-
WHERE path LIKE '%.postgres-wrapped%'
227-
AND cmdline LIKE '%-D /etc/postgresql%';
228-
"""
229-
query_result = run_osquery(query)
230-
parsed_result = parse_json(query_result)
231-
232-
pid = parsed_result[0].get("pid")
233-
234-
# get the mounts for the process
227+
"""Check that postgresql.service mounts /etc as read-only."""
228+
# Find the postgres process by reading /proc
229+
# We're looking for a process with .postgres-wrapped in the path
230+
# and -D /etc/postgresql in the command line
231+
pid = None
232+
233+
for proc_dir in os.listdir("/proc"):
234+
if not proc_dir.isdigit():
235+
continue
236+
237+
try:
238+
# Read the command line
239+
with open(f"/proc/{proc_dir}/cmdline", "r") as f:
240+
cmdline = f.read()
241+
# Check if this is a postgres process with the right data directory
242+
if ".postgres-wrapped" in cmdline and "-D /etc/postgresql" in cmdline:
243+
pid = proc_dir
244+
break
245+
except (FileNotFoundError, PermissionError):
246+
# Process might have disappeared or we don't have permission
247+
continue
248+
249+
if pid is None:
250+
print(
251+
"Could not find postgres process with .postgres-wrapped and -D /etc/postgresql"
252+
)
253+
sys.exit(1)
254+
255+
# Get the mounts for the process
235256
with open(f"/proc/{pid}/mounts", "r") as o:
236257
lines = [line for line in o if "/etc" in line and "ro," in line]
237258
if len(lines) == 0:
@@ -265,9 +286,6 @@ def check_directory_permissions():
265286
actual_mode = oct(stat.S_IMODE(stat_info.st_mode))[2:] # Remove '0o' prefix
266287

267288
# Get owner and group names
268-
import pwd
269-
import grp
270-
271289
actual_owner = pwd.getpwuid(stat_info.st_uid).pw_name
272290
actual_group = grp.getgrgid(stat_info.st_gid).gr_name
273291

@@ -369,12 +387,10 @@ def main():
369387
if not qemu_artifact:
370388
usernames.append("ec2-instance-connect")
371389

372-
# Iterate over usernames, run the query, and compare results
390+
# Iterate over usernames, get their groups, and compare results
373391
for username in usernames:
374-
query = f"SELECT u.username, g.groupname FROM users u JOIN user_groups ug ON u.uid = ug.uid JOIN groups g ON ug.gid = g.gid WHERE u.username = '{username}' ORDER BY g.groupname;"
375-
query_result = run_osquery(query)
376-
parsed_result = parse_json(query_result)
377-
compare_results(username, parsed_result)
392+
user_groups = get_user_groups(username)
393+
compare_results(username, user_groups)
378394

379395
# Check if all nixbld users are in the nixbld group
380396
check_nixbld_users()

ansible/playbook.yml

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -204,17 +204,11 @@
204204
apt autoremove -y --purge snapd
205205
when: stage2_nix
206206

207-
- name: Install osquery from nixpkgs binary cache
208-
become: yes
209-
shell: |
210-
sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install github:nixos/nixpkgs/f98ec4f73c762223d62bee706726138cb6ea27cc#osquery"
211-
when: stage2_nix
212-
213-
- name: Run osquery permission checks
207+
- name: Run permission checks
214208
become: yes
215209
shell: |
216210
systemctl start postgresql.service
217-
sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && /usr/bin/python3 /tmp/ansible-playbook/ansible/files/permission_check.py {{ '--qemu' if qemu_mode is defined else '' }}"
211+
/usr/bin/python3 /tmp/ansible-playbook/ansible/files/permission_check.py {{ '--qemu' if qemu_mode is defined else '' }}
218212
systemctl stop postgresql.service
219213
when: stage2_nix
220214

@@ -226,12 +220,6 @@
226220
systemctl stop fail2ban.service
227221
when: stage2_nix
228222

229-
- name: Remove osquery
230-
become: yes
231-
shell: |
232-
sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile remove osquery"
233-
when: stage2_nix
234-
235223
- name: nix collect garbage
236224
become: yes
237225
shell: |

ansible/tasks/setup-wal-g.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,21 @@
3333
cmd: sudo -u wal-g bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install github:supabase/postgres/{{ git_commit_sha }}#wal-g-2"
3434
become: true
3535

36+
- name: nix collect garbage
37+
ansible.builtin.shell:
38+
cmd: sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix-collect-garbage -d"
39+
become: true
40+
3641
- name: Install wal-g 3 from nix binary cache
3742
ansible.builtin.shell:
3843
cmd: sudo -u wal-g bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install github:supabase/postgres/{{ git_commit_sha }}#wal-g-3"
3944
become: true
4045

46+
- name: nix collect garbage
47+
ansible.builtin.shell:
48+
cmd: sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix-collect-garbage -d"
49+
become: true
50+
4151
- name: Create symlink for wal-g-3 from Nix profile to /usr/local/bin
4252
ansible.builtin.file:
4353
dest: '/usr/local/bin/wal-g-v3'

ansible/vars.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ postgres_exporter_release_checksum:
5555

5656
adminapi_release: "0.93.0"
5757
adminmgr_release: "0.32.3"
58-
supabase_admin_agent_release: 1.4.38
58+
supabase_admin_agent_release: 1.6.0
5959
supabase_admin_agent_splay: 30s
6060

6161
vector_x86_deb: https://packages.timber.io/vector/0.48.X/vector_0.48.0-1_amd64.deb

stage2-nix-psql.pkr.hcl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ source "amazon-ebs" "ubuntu" {
8181

8282
associate_public_ip_address = true
8383

84+
# Increase timeout for instance stop operations to handle large instances
85+
aws_polling {
86+
delay_seconds = 15
87+
max_attempts = 120 # 120 * 15s = 30 minutes max wait
88+
}
8489

8590
ena_support = true
8691

0 commit comments

Comments
 (0)