121 lines
4.2 KiB
Markdown
121 lines
4.2 KiB
Markdown
# Authentik deployment
|
|
|
|
This repository owns the production Authentik Compose deployment and its
|
|
Komodo Stack declaration. The central `komodo-bootstrap` repository owns the
|
|
child Resource Sync and the ordered deployment Procedure.
|
|
|
|
## Layout
|
|
|
|
```text
|
|
.
|
|
├── docker-compose.yml
|
|
├── docker-compose.override.yml
|
|
├── komodo.toml
|
|
├── env/
|
|
│ └── common.env
|
|
├── secrets/
|
|
│ └── prod.env.age
|
|
├── scripts/
|
|
│ ├── compose.sh
|
|
│ └── init.sh
|
|
└── tests/
|
|
└── compose-secrets.sh
|
|
```
|
|
|
|
`env/common.env` contains tracked, non-secret configuration and explicit image
|
|
versions. `secrets/prod.env.age` contains only secrets and is encrypted to the
|
|
`sbx0docker01` SSH host key and the personal `agenix-phg` SSH key.
|
|
|
|
The `authentik-prod` Stack follows protected `main`. Its direct webhook is
|
|
disabled. A Forgejo webhook calls the central `authentik-deploy` Procedure,
|
|
which runs the child Sync before `DeployStackIfChanged`.
|
|
|
|
Komodo passes `docker-compose.yml` first and `docker-compose.override.yml`
|
|
second. The base and deployment-specific override remain separate by design.
|
|
|
|
## Secrets
|
|
|
|
The encrypted production bundle contains:
|
|
|
|
```text
|
|
PG_PASS
|
|
AUTHENTIK_SECRET_KEY
|
|
AUTHENTIK_EMAIL__PASSWORD
|
|
GEOIPUPDATE_LICENSE_KEY
|
|
```
|
|
|
|
To edit it locally, decrypt to a mode-`0600` temporary file, edit it, then
|
|
encrypt it to both recipients:
|
|
|
|
```bash
|
|
tmp=$(mktemp)
|
|
chmod 0600 "$tmp"
|
|
trap 'rm -f -- "$tmp"' EXIT HUP INT TERM
|
|
|
|
age --decrypt \
|
|
--identity ~/.ssh/identities/agenix-phg \
|
|
--output "$tmp" \
|
|
secrets/prod.env.age
|
|
|
|
${EDITOR:-vi} "$tmp"
|
|
|
|
age --encrypt \
|
|
--armor \
|
|
--recipient 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4umkUY5CG5aNJBhUjVcU8TWbh453N0pGHZhYDTOGQa' \
|
|
--recipient 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIr4Dji0wWzwSXyqbxdGa8LdWkhP+0T7kDKrLbyCoyos' \
|
|
--output secrets/prod.env.age.new \
|
|
"$tmp"
|
|
|
|
mv secrets/prod.env.age.new secrets/prod.env.age
|
|
```
|
|
|
|
Do not add a plaintext secret file to Git. The Stack config tracks the
|
|
encrypted bundle so a rotation counts as a deployment change, but does not
|
|
track the temporary `.komodo/prod.env` file.
|
|
|
|
The decrypted values are Compose secret sources rather than service
|
|
environment values. Containers receive only their declared files under
|
|
`/run/secrets`; Authentik reads them through `file://` configuration values,
|
|
while PostgreSQL and GeoIP Update use their `_FILE` variables. Consequently,
|
|
`docker compose config` renders secret source names and file paths without
|
|
persisting the values in Komodo's merged configuration.
|
|
|
|
## Compose wrapper
|
|
|
|
Komodo wraps `config`, `pull`, `up`, and `run` with
|
|
the NixOS-provided `with-age-env` command. The wrapper:
|
|
|
|
- obtains an exclusive per-bundle lock;
|
|
- removes stale plaintext and temporary files;
|
|
- decrypts through the NixOS-provided systemd `age-identity` credential;
|
|
- creates plaintext with mode `0600`; and
|
|
- removes plaintext on success, failure, or a handled signal.
|
|
|
|
The plaintext target and matching `.lock` and `.tmp.*` paths are exclusively
|
|
owned by the wrapper. A `SIGKILL` or power loss can leave plaintext behind;
|
|
the next invocation removes it before decrypting again.
|
|
|
|
NixOS owns the wrapper, its runtime dependencies, the host-key systemd
|
|
credential, Periphery's Podman permissions, and the external
|
|
`dokploy-network`. Workload containers do not receive the age identity, but
|
|
commands launched by Periphery can access it. Revisit that trust boundary if
|
|
deployment authority is ever granted to another operator.
|
|
|
|
Run `bash tests/compose-secrets.sh` to verify that sentinel secret values do
|
|
not appear in the rendered Compose model and that every service receives only
|
|
its intended secret files.
|
|
|
|
## Optional test environment
|
|
|
|
Do not create a test Stack or dummy bundle until there is a real long-lived
|
|
`test` branch. When it is needed:
|
|
|
|
1. add `secrets/test.env.age`, encrypted to the test host and personal keys;
|
|
2. keep both Stack declarations in `komodo.toml` on `main`;
|
|
3. point `authentik-test` at branch `test` and its own encrypted/decrypted
|
|
paths; and
|
|
4. add `authentik-test` to the Procedure's deployment stage in the central
|
|
bootstrap repository.
|
|
|
|
The repository webhook should use the Procedure's `__ANY__` endpoint so pushes
|
|
to either protected environment branch enter the same ordered flow.
|