Skip to content

Commit e0a5405

Browse files
authored
feat: supascan audit feature (#1963)
* feat: audit feature * feat: shallow dirs * feat: include dirs * fix: deal with various dirs * fix: excludes * feat: baseline test * tests: upload baseline * fix: move audit to end of image build * feat: supascan * fix: cleanup * fix: upload * fix: consolidate installation etc * fix: install * fix: sudo for validate * fix: ubuntu user path * feat: organize into ami build and deployed * fix: rename * fix: package not present at ami build * fix: include users, groups perms * fix: align perms with build stage * fix: restore sh files undo formatting * chore: restore version in package * fix: update conf.d * chore: rename task
1 parent 1081090 commit e0a5405

File tree

86 files changed

+199173
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+199173
-7
lines changed

ansible/files/supascan_ami.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/bash
2+
# Baseline Validation Check
3+
#
4+
# This script validates that the machine matches the committed baseline
5+
# specifications using supascan (pre-installed via nix profile for ubuntu user).
6+
#
7+
# Usage: supascan_ami.sh [baselines-dir]
8+
9+
set -euo pipefail
10+
11+
BASELINES_DIR="${1:-/tmp/ansible-playbook/audit-specs/baselines/ami-build}"
12+
13+
echo "============================================================"
14+
echo "Baseline Validation"
15+
echo "============================================================"
16+
echo ""
17+
echo "Baselines directory: $BASELINES_DIR"
18+
echo ""
19+
20+
# Check baselines directory exists
21+
if [[ ! -d $BASELINES_DIR ]]; then
22+
echo "ERROR: Baselines directory not found: $BASELINES_DIR"
23+
exit 1
24+
fi
25+
26+
# Add ubuntu user's nix profile to PATH
27+
export PATH="/home/ubuntu/.nix-profile/bin:$PATH"
28+
29+
# Verify supascan is available
30+
if ! command -v supascan &>/dev/null; then
31+
echo "ERROR: supascan not found in PATH"
32+
echo "PATH: $PATH"
33+
exit 1
34+
fi
35+
36+
# Run supascan validate (it calls sudo goss internally for privileged checks)
37+
exec supascan validate --verbose "$BASELINES_DIR"

ansible/playbook.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@
220220
systemctl stop fail2ban.service
221221
when: stage2_nix
222222

223+
- name: Run supascan baseline validation
224+
become: yes
225+
shell: |
226+
/bin/bash /tmp/ansible-playbook/ansible/files/supascan_ami.sh /tmp/ansible-playbook/audit-specs/baselines/ami-build
227+
when: stage2_nix
228+
229+
- name: Remove supascan after validation
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 supascan"
233+
when: stage2_nix
234+
223235
- name: nix collect garbage
224236
become: yes
225237
shell: |

ansible/tasks/stage2-setup-postgres.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@
106106
loop_control:
107107
loop_var: 'nix_item'
108108

109+
- name: Install supascan for baseline validation
110+
ansible.builtin.shell: |
111+
sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix profile install github:supabase/postgres/{{ git_commit_sha }}#supascan"
112+
113+
- name: nix collect garbage after supascan install
114+
ansible.builtin.shell:
115+
cmd: sudo -u ubuntu bash -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix-collect-garbage -d"
116+
109117
- name: Set ownership and permissions for file and dirs
110118
ansible.builtin.file:
111119
group: 'postgres'

audit-specs/baselines/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Machine Baselines
2+
3+
This directory contains captured baselines from real machines.
4+
5+
## Generating a Baseline
6+
7+
On your target machine:
8+
```bash
9+
sudo nix run github:supabase/ubuntu-cis-audit#cis-generate-spec -- baseline.yaml
10+
```
11+
12+
## Naming Convention
13+
14+
Use descriptive names that identify the machine type or environment:
15+
- `production-db-baseline.yaml` - Production database server
16+
- `staging-api-baseline.yaml` - Staging API server
17+
- `postgres-baseline.yaml` - Standard PostgreSQL server config
18+
19+
## Using Baselines
20+
21+
Copy your baseline to this directory and commit to git. Then use GOSS to audit other machines:
22+
23+
```bash
24+
# On target machine
25+
goss --gossfile audit-specs/baselines/production-db-baseline.yaml validate
26+
```
27+
28+
## Baseline Sources
29+
30+
Document where each baseline came from:
31+
32+
- `postgres-baseline.yaml` - Generated from db-pdnxwzxvlrfwogpyaltm on 2025-11-22
33+
- `production-baseline.yaml` - Generated from prod-server-001 on 2025-11-20
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# File baseline: postgres-config
2+
# PostgreSQL configuration files for AMI build
3+
# Uses string names for owner/group (not numeric IDs)
4+
file:
5+
# Main PostgreSQL config directory
6+
/etc/postgresql:
7+
exists: true
8+
filetype: directory
9+
owner: postgres
10+
group: postgres
11+
mode: '0775'
12+
/etc/postgresql/postgresql.conf:
13+
exists: true
14+
filetype: file
15+
owner: root
16+
group: root
17+
mode: '0644'
18+
/etc/postgresql/pg_hba.conf:
19+
exists: true
20+
filetype: file
21+
owner: root
22+
group: postgres
23+
mode: '0664'
24+
/etc/postgresql/pg_ident.conf:
25+
exists: true
26+
filetype: file
27+
owner: root
28+
group: postgres
29+
mode: '0644'
30+
/etc/postgresql/logging.conf:
31+
exists: true
32+
filetype: file
33+
owner: root
34+
group: postgres
35+
mode: '0644'
36+
37+
# Custom PostgreSQL config directory
38+
/etc/postgresql-custom:
39+
exists: true
40+
filetype: directory
41+
owner: postgres
42+
group: postgres
43+
mode: '0775'
44+
# Note: platform-defaults.conf and pgsodium_root.key are created at deploy time
45+
/etc/postgresql-custom/custom-overrides.conf:
46+
exists: true
47+
filetype: file
48+
owner: postgres
49+
group: postgres
50+
mode: '0664'
51+
/etc/postgresql-custom/generated-optimizations.conf:
52+
exists: true
53+
filetype: file
54+
owner: postgres
55+
group: postgres
56+
mode: '0664'
57+
/etc/postgresql-custom/supautils.conf:
58+
exists: true
59+
filetype: file
60+
owner: postgres
61+
group: postgres
62+
mode: '0664'
63+
/etc/postgresql-custom/conf.d:
64+
exists: true
65+
filetype: directory
66+
owner: postgres
67+
group: postgres
68+
mode: '0775'
69+
/etc/postgresql-custom/conf.d/wal-g.conf:
70+
exists: true
71+
filetype: file
72+
owner: postgres
73+
group: postgres
74+
mode: '0664'
75+
/etc/postgresql-custom/conf.d/read_replica.conf:
76+
exists: true
77+
filetype: file
78+
owner: postgres
79+
group: postgres
80+
mode: '0664'
81+
82+
# Extension custom scripts directory
83+
/etc/postgresql-custom/extension-custom-scripts:
84+
exists: true
85+
filetype: directory
86+
owner: postgres
87+
group: postgres
88+
mode: '0775'
89+
/etc/postgresql-custom/extension-custom-scripts/before-create.sql:
90+
exists: true
91+
filetype: file
92+
owner: postgres
93+
group: postgres
94+
mode: '0775'
95+
96+
# PostgREST config directory
97+
/etc/postgrest:
98+
exists: true
99+
filetype: directory
100+
owner: postgrest
101+
group: postgrest
102+
mode: '0775'
103+
/etc/postgrest/base.conf:
104+
exists: true
105+
filetype: file
106+
owner: postgrest
107+
group: postgrest
108+
mode: '0644'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# File baseline: postgres-data
2+
# PostgreSQL data directory for AMI build
3+
# Uses string names for owner/group (not numeric IDs)
4+
file:
5+
# PostgreSQL data directory
6+
/var/lib/postgresql:
7+
exists: true
8+
filetype: directory
9+
owner: postgres
10+
group: postgres
11+
mode: '0755'
12+
# Note: /var/lib/postgresql/data is a symlink during AMI build (points to /data/...)
13+
# The actual data directory is created at deploy time
14+
/var/lib/postgresql/data:
15+
exists: true
16+
filetype: symlink
17+
owner: root
18+
group: root
19+
mode: '0777'
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# File baseline: security
2+
# Critical security-related files for AMI build
3+
# Uses string names for owner/group (not numeric IDs)
4+
file:
5+
# fail2ban configuration directory
6+
/etc/fail2ban:
7+
exists: true
8+
filetype: directory
9+
owner: root
10+
group: root
11+
mode: '0755'
12+
/etc/fail2ban/jail.local:
13+
exists: true
14+
filetype: file
15+
owner: root
16+
group: root
17+
mode: '0644'
18+
19+
# AppArmor
20+
/etc/apparmor.d:
21+
exists: true
22+
filetype: directory
23+
owner: root
24+
group: root
25+
mode: '0755'
26+
27+
# UFW firewall
28+
/etc/ufw:
29+
exists: true
30+
filetype: directory
31+
owner: root
32+
group: root
33+
mode: '0755'
34+
/etc/ufw/ufw.conf:
35+
exists: true
36+
filetype: file
37+
owner: root
38+
group: root
39+
mode: '0644'
40+
41+
# SSH configuration
42+
/etc/ssh/sshd_config:
43+
exists: true
44+
filetype: file
45+
owner: root
46+
group: root
47+
mode: '0644'
48+
49+
# PAM configuration
50+
/etc/pam.d:
51+
exists: true
52+
filetype: directory
53+
owner: root
54+
group: root
55+
mode: '0755'
56+
57+
# Sudoers
58+
/etc/sudoers:
59+
exists: true
60+
filetype: file
61+
owner: root
62+
group: root
63+
mode: '0440'
64+
/etc/sudoers.d:
65+
exists: true
66+
filetype: directory
67+
owner: root
68+
group: root
69+
mode: '0750'
70+
71+
# Security limits
72+
/etc/security/limits.conf:
73+
exists: true
74+
filetype: file
75+
owner: root
76+
group: root
77+
mode: '0644'
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# File baseline: ssl
2+
# SSL certificate and key directories for AMI build
3+
# Uses string names for owner/group (not numeric IDs)
4+
file:
5+
# System SSL directory
6+
/etc/ssl:
7+
exists: true
8+
filetype: directory
9+
owner: root
10+
group: root
11+
mode: '0755'
12+
/etc/ssl/certs:
13+
exists: true
14+
filetype: directory
15+
owner: root
16+
group: root
17+
mode: '0755'
18+
/etc/ssl/private:
19+
exists: true
20+
filetype: directory
21+
owner: root
22+
group: postgres
23+
mode: '0750'
24+
/etc/ssl/openssl.cnf:
25+
exists: true
26+
filetype: file
27+
owner: root
28+
group: root
29+
mode: '0644'
30+
# Note: /etc/ssl/adminapi is created at deploy time, not during AMI build

0 commit comments

Comments
 (0)