Skip to content
Closed
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
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,26 @@ Brio staging uses only its isolated encrypted overlay and certificate-matching a
postgres://brio_staging_app:<secret>@makepad-postgres-brio-staging:5432/brio_staging?sslmode=verify-full&sslrootcert=/etc/brio/postgres/ca.crt
```

Brio release evidence observes the shared database runtime without receiving a
database or deployment credential. After deriving the public half of Brio's
dedicated release-observer SSH key from its canonical Proton Pass item, install
the bounded host observer once as root:

```sh
scripts/install-brio-runtime-observer.sh \
scripts/brio-runtime-observe.sh \
/secure/operator-path/brio-release-observer.pub
```

The installer creates a locked `brio-runtime-observer` account whose key is
bound with OpenSSH `restrict` to one root-owned command. The command accepts
only `shared-runtime-observe`; it verifies the exact healthy standalone
`postgres/postgres` Compose unit, binds the running image content to its
immutable reference, and returns bounded image, version, and lifecycle JSON.
It cannot read database data, container environment or mounts, run arbitrary
Docker commands, or mutate the host. Never install a deployment key for this
account or mirror the observer private key to this repository.

If production overrides `DEPLOY_VIF_DB_NAME` or `DEPLOY_VIF_DB_USER`, use those values in the connection URI.

## Validation
Expand All @@ -725,6 +745,7 @@ Run the static deployment checks and the disposable PostgreSQL 16 bootstrap test
./scripts/test-brio-deploy-guards.sh
./scripts/test-brio-deployment-contracts.sh
./scripts/test-brio-deployment-failures.sh
./scripts/test-brio-runtime-observer.sh
```

Run the local static checks before opening a deployment PR:
Expand All @@ -738,4 +759,5 @@ bash scripts/test-brio-encrypted-restore.sh
bash scripts/test-brio-deploy-guards.sh
bash scripts/test-brio-deployment-contracts.sh
bash scripts/test-brio-deployment-failures.sh
bash scripts/test-brio-runtime-observer.sh
```
84 changes: 84 additions & 0 deletions scripts/brio-runtime-observe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -Eeuo pipefail

export PATH=/usr/bin:/bin
umask 077

readonly expected_command=shared-runtime-observe
readonly expected_container=postgres-postgres-1
readonly expected_project=postgres
readonly expected_service=postgres
readonly expected_image=postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
readonly expected_version=16.14
readonly image_id_pattern='^sha256:[a-f0-9]{64}$'

die() {
printf '%s\n' "$1" >&2
exit 1
}

docker_short() {
timeout --signal=KILL 20s docker "$@"
}

(( EUID == 0 )) || die 'The Brio PostgreSQL runtime observer must run through its exact passwordless sudo rule.'
[[ "${SSH_ORIGINAL_COMMAND:-}" == "${expected_command}" ]] || \
die 'The Brio PostgreSQL runtime observer accepts only shared-runtime-observe.'

record=$(docker_short inspect --type container --format \
'{{.Id}}|{{.Name}}|{{.Config.Image}}|{{.Image}}|{{.State.Status}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}missing{{end}}|{{.State.StartedAt}}|{{.RestartCount}}|{{index .Config.Labels "com.docker.compose.project"}}|{{index .Config.Labels "com.docker.compose.service"}}|{{index .Config.Labels "com.docker.compose.oneoff"}}|{{index .Config.Labels "com.docker.compose.config-hash"}}|{{.HostConfig.NetworkMode}}' \
"${expected_container}") || die 'Cannot inspect the shared PostgreSQL container.'
IFS='|' read -r container_id container_name image runtime_image_id state health started_at restart_count \
compose_project compose_service compose_oneoff config_hash network_mode <<< "${record}"

[[ "${container_id}" =~ ^[a-f0-9]{64}$ && "${container_name}" == "/${expected_container}" ]] || \
die 'Shared PostgreSQL returned an invalid container identity.'
[[ "${image}" == "${expected_image}" && "${runtime_image_id}" =~ ${image_id_pattern} ]] || \
die 'Shared PostgreSQL is not running an immutable reviewed image reference.'
[[ "${state}" == running && "${health}" == healthy ]] || die 'Shared PostgreSQL is not running and healthy.'
[[ "${compose_project}" == "${expected_project}" && "${compose_service}" == "${expected_service}" \
&& "${compose_oneoff}" == False && "${network_mode}" == host ]] || \
die 'Shared PostgreSQL has unexpected Compose identity or network mode.'
[[ "${config_hash}" =~ ^[a-f0-9]{64}$ ]] || die 'Shared PostgreSQL has an invalid Compose configuration digest.'
[[ "${started_at}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?Z$ && \
"${restart_count}" =~ ^[0-9]+$ ]] || \
die 'Shared PostgreSQL returned invalid lifecycle identity.'

resolved_image_id=$(docker_short image inspect "${image}" --format '{{.Id}}') || \
die 'Cannot resolve the shared PostgreSQL immutable image reference.'
[[ "${resolved_image_id}" == "${runtime_image_id}" ]] || \
die 'Shared PostgreSQL container content does not match its immutable image reference.'
version_output=$(docker_short exec "${container_id}" postgres --version 2>&1) || \
die 'Cannot read the running PostgreSQL version.'
(( ${#version_output} <= 128 )) || die 'Shared PostgreSQL returned an oversized runtime version.'
[[ "${version_output}" =~ ^postgres\ \(PostgreSQL\)\ (16\.[0-9]+)(\.[0-9]+)?$ ]] || \
die 'Shared PostgreSQL returned an unexpected runtime version.'
version=${BASH_REMATCH[1]}${BASH_REMATCH[2]:-}
[[ "${version}" == "${expected_version}" ]] || die 'Shared PostgreSQL is not running the reviewed 16.14 runtime.'

python3 - "${image}" "${runtime_image_id}" "${version}" "${container_id}" \
"${started_at}" "${restart_count}" "${config_hash}" <<'PY'
import json
import sys

image, image_id, version, container_id, started_at, restart_count, config_hash = sys.argv[1:]
payload = {
"schema": "makepad.brio.runtime-host-observation.v1",
"hostRole": "database",
"components": [{
"name": "postgres",
"orchestrator": "compose",
"unit": "postgres/postgres",
"image": image,
"runtimeImageID": image_id,
"configDigest": f"sha256:{config_hash}",
"version": version,
"state": "running",
"health": "healthy",
"instanceID": f"sha256:{container_id}",
"startedAt": started_at,
"restartCount": int(restart_count),
}],
}
print(json.dumps(payload, sort_keys=True, separators=(",", ":")))
PY
89 changes: 89 additions & 0 deletions scripts/install-brio-runtime-observer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
set -Eeuo pipefail

export PATH=/usr/sbin:/usr/bin:/sbin:/bin
export LANG=C
export LC_ALL=C
umask 077

readonly observer_user=brio-runtime-observer
readonly observer_home=/var/lib/brio-runtime-observer
readonly observer_command=/usr/local/libexec/makepad/brio-postgres-runtime-observe
readonly sudoers_path=/etc/sudoers.d/brio-postgres-runtime-observer

die() {
printf '%s\n' "$1" >&2
exit 1
}

(( EUID == 0 )) || die 'Run this installer as root on the PostgreSQL host.'
[[ $# == 2 ]] || die 'usage: install-brio-runtime-observer.sh OBSERVER_SCRIPT ED25519_PUBLIC_KEY_FILE'
for command_name in cmp docker getent id install mktemp passwd python3 ssh-keygen stat timeout useradd visudo wc; do
command -v "${command_name}" >/dev/null || die "Missing required installer command: ${command_name}."
done
source_script=$1
public_key_file=$2
[[ -f "${source_script}" && ! -L "${source_script}" ]] || die 'Observer source must be a regular file.'
[[ -f "${public_key_file}" && ! -L "${public_key_file}" ]] || die 'Observer public key must be a regular file.'
[[ $(wc -c < "${source_script}") -le 65536 ]] || die 'Observer source is unexpectedly large.'
[[ $(wc -c < "${public_key_file}") -le 1024 ]] || die 'Observer public key file is unexpectedly large.'

read -r key_type key_body key_extra < "${public_key_file}"
[[ "${key_type}" == ssh-ed25519 && "${key_body}" =~ ^[A-Za-z0-9+/]+={0,3}$ && -z "${key_extra:-}" ]] || \
die 'Expected exactly one OpenSSH Ed25519 public key without trailing fields.'
[[ $(wc -l < "${public_key_file}") -eq 1 ]] || die 'Observer public key file must contain exactly one line.'
ssh-keygen -l -f "${public_key_file}" >/dev/null || die 'Observer public key is not valid OpenSSH key material.'

if ! id "${observer_user}" >/dev/null 2>&1; then
useradd --system --user-group --create-home --home-dir "${observer_home}" --shell /bin/bash "${observer_user}"
fi
account_record=$(getent passwd "${observer_user}") || die 'Observer account could not be read.'
IFS=: read -r account_name _ account_uid _ _ account_home account_shell <<< "${account_record}"
[[ "${account_name}" == "${observer_user}" && "${account_uid}" =~ ^[1-9][0-9]*$ && \
"${account_uid}" -lt 1000 && "${account_home}" == "${observer_home}" && \
"${account_shell}" == /bin/bash && "$(id -gn "${observer_user}")" == "${observer_user}" && \
"$(id -nG "${observer_user}")" == "${observer_user}" ]] || die 'Observer account identity is unsafe.'
passwd --lock "${observer_user}" >/dev/null
read -r _ password_state _ <<< "$(passwd --status "${observer_user}")"
[[ "${password_state}" == L ]] || die 'Observer account password is not locked.'

install -d -o root -g root -m 0755 /usr/local/libexec /usr/local/libexec/makepad
for controlled_path in "${observer_command}" "${sudoers_path}" "${observer_home}" \
"${observer_home}/.ssh" "${observer_home}/.ssh/authorized_keys"; do
[[ ! -L "${controlled_path}" ]] || die "Refusing symbolic link at managed path: ${controlled_path}."
done
[[ ! -e "${observer_command}" || -f "${observer_command}" ]] || die 'Observer command path has an unsafe file type.'
[[ ! -e "${sudoers_path}" || -f "${sudoers_path}" ]] || die 'Observer sudo rule path has an unsafe file type.'
[[ ! -e "${observer_home}" || -d "${observer_home}" ]] || die 'Observer home has an unsafe file type.'
[[ ! -e "${observer_home}/.ssh" || -d "${observer_home}/.ssh" ]] || die 'Observer SSH path has an unsafe file type.'
[[ ! -e "${observer_home}/.ssh/authorized_keys" || -f "${observer_home}/.ssh/authorized_keys" ]] || \
die 'Observer authorized-keys path has an unsafe file type.'

install -o root -g root -m 0755 -T "${source_script}" "${observer_command}"
install -d -o root -g root -m 0755 "${observer_home}"
install -d -o root -g root -m 0700 "${observer_home}/.ssh"

authorized_keys=$(mktemp)
sudoers_candidate=$(mktemp)
trap 'rm -f -- "${authorized_keys}" "${sudoers_candidate}"' EXIT
printf 'restrict,command="/usr/bin/sudo -n %s" %s %s\n' \
"${observer_command}" "${key_type}" "${key_body}" > "${authorized_keys}"
install -o root -g root -m 0600 -T \
"${authorized_keys}" "${observer_home}/.ssh/authorized_keys"

printf 'Defaults!%s env_keep += "SSH_ORIGINAL_COMMAND"\n' "${observer_command}" > "${sudoers_candidate}"
printf '%s ALL=(root) NOPASSWD: %s\n' "${observer_user}" "${observer_command}" >> "${sudoers_candidate}"
chmod 0440 "${sudoers_candidate}"
visudo -cf "${sudoers_candidate}" >/dev/null
install -o root -g root -m 0440 -T "${sudoers_candidate}" "${sudoers_path}"

[[ "$(stat -c '%U:%G:%a' "${observer_command}")" == root:root:755 ]] || die 'Observer command permissions are unsafe.'
[[ "$(stat -c '%U:%G:%a' "${sudoers_path}")" == root:root:440 ]] || die 'Observer sudo rule permissions are unsafe.'
[[ "$(stat -c '%U:%G:%a' "${observer_home}")" == root:root:755 ]] || die 'Observer home permissions are unsafe.'
[[ "$(stat -c '%U:%G:%a' "${observer_home}/.ssh")" == root:root:700 ]] || die 'Observer SSH directory permissions are unsafe.'
[[ "$(stat -c '%U:%G:%a' "${observer_home}/.ssh/authorized_keys")" == \
root:root:600 ]] || die 'Observer authorized_keys permissions are unsafe.'
cmp -s "${source_script}" "${observer_command}" || die 'Installed observer differs from the reviewed source.'
cmp -s "${authorized_keys}" "${observer_home}/.ssh/authorized_keys" || die 'Installed authorized key differs from the reviewed candidate.'
cmp -s "${sudoers_candidate}" "${sudoers_path}" || die 'Installed sudo rule differs from the reviewed candidate.'
visudo -cf "${sudoers_path}" >/dev/null || die 'Installed observer sudo rule is invalid.'
4 changes: 4 additions & 0 deletions scripts/run-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ shellcheck_paths=( \
scripts/install-keycloak-cohort-cleaner.sh \
scripts/keycloak-cohort-capture-dispatch.sh \
scripts/install-keycloak-cohort-capture-host.sh \
scripts/brio-runtime-observe.sh \
scripts/install-brio-runtime-observer.sh \
scripts/verify-brio-encrypted-restore.sh \
scripts/test-brio-bootstrap.sh \
scripts/test-brio-db-transaction.sh \
Expand All @@ -28,6 +30,7 @@ shellcheck_paths=( \
scripts/test-brio-deployment-contracts.sh \
scripts/test-brio-deployment-failures.sh \
scripts/test-brio-release-evidence.sh \
scripts/test-brio-runtime-observer.sh \
scripts/test-keycloak-cohort-evidence.sh \
scripts/test-keycloak-cohort-hardening.sh \
scripts/capture-keycloak-cohort-backups.sh \
Expand Down Expand Up @@ -62,6 +65,7 @@ git diff --check
./scripts/test-brio-deployment-contracts.sh
./scripts/test-brio-deployment-failures.sh
./scripts/test-brio-release-evidence.sh
./scripts/test-brio-runtime-observer.sh
./scripts/test-keycloak-cohort-evidence.sh
./scripts/test-keycloak-cohort-hardening.sh
./scripts/test-brio-bootstrap.sh
Expand Down
54 changes: 54 additions & 0 deletions scripts/test-brio-runtime-observer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -Eeuo pipefail

repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
observer=${repo_root}/scripts/brio-runtime-observe.sh
installer=${repo_root}/scripts/install-brio-runtime-observer.sh

for path in "${observer}" "${installer}"; do
[[ -f "${path}" && ! -L "${path}" ]] || { echo "missing runtime observer artifact: ${path}" >&2; exit 1; }
bash -n "${path}"
done

for marker in \
'export PATH=/usr/bin:/bin' \
'SSH_ORIGINAL_COMMAND:-' \
'shared-runtime-observe' \
'timeout --signal=KILL 20s docker' \
'readonly expected_container=postgres-postgres-1' \
'postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777' \
'com.docker.compose.project' \
'com.docker.compose.service' \
'com.docker.compose.config-hash' \
'configDigest' \
'runtimeImageID' \
'postgres --version' \
'readonly expected_version=16.14' \
'makepad.brio.runtime-host-observation.v1'; do
grep -Fq -- "${marker}" "${observer}" || { echo "observer is missing ${marker}" >&2; exit 1; }
done

for forbidden in 'Config.Env' 'Mounts' 'docker logs'; do
! grep -Fq -- "${forbidden}" "${observer}" || { echo "observer contains forbidden inspection: ${forbidden}" >&2; exit 1; }
done

for marker in \
'readonly observer_user=brio-runtime-observer' \
'export PATH=/usr/sbin:/usr/bin:/sbin:/bin' \
'useradd --system --user-group' \
'getent passwd' \
'id -nG' \
'ssh-keygen -l -f' \
'Refusing symbolic link at managed path' \
'restrict,command="/usr/bin/sudo -n %s"' \
'env_keep += "SSH_ORIGINAL_COMMAND"' \
'NOPASSWD:' \
'visudo -cf' \
'passwd --lock' \
'passwd --status' \
'root:root:700' \
'cmp -s'; do
grep -Fq -- "${marker}" "${installer}" || { echo "installer is missing ${marker}" >&2; exit 1; }
done

echo 'Brio PostgreSQL runtime observer contract passed.'