# Security and demo-only defaults ← Back to [Architecture index](README.md) > This repo is explicitly designed for **demo setups**. All default > values in the roles are insecure and are overridden in `demo-*` > inventories via Bao lookups or host_vars. For production deployments > the hardening block further down also applies. ## Secret pattern (Bao lookup) ```yaml # group_vars/.../.yml or host_vars/.../.yml authentik_secret_key: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik:secret_key', url=vault_addr) }}" ``` - `vault_mount` and `vault_addr` come from [group_vars/all/vault.yml](https://git.digitalboard.ch/Digitalboard/reference-ansible/src/branch/main/inventories/demo-gymburgdorf/group_vars/all/vault.yml). - KV-v2 paths require an explicit `/data/` segment — Ansible does not resolve this automatically. - `vault_mount` is unique per inventory (`demo-gymburgdorf`, `demo-phbern`, …) → tenant isolation in Bao via mount + policy. ## Demo-only defaults — override required These defaults in `digitalboard.core` are insecure. In any **production-grade** deployment they must be overridden via Bao lookup or host_var: | Variable | Default | Where to override | |---|---|---| | `keycloak_admin_password` | `changeme` | host_vars `keycloak_servers` | | `keycloak_postgres_password` | `changeme` | same | | `authentik_secret_key` | `changeme-generate-a-random-string` | `host_vars/application/authentik.yml` | | `authentik_postgres_password` | `changeme` | same | | `nextcloud_admin_password` | `admin` | `host_vars/application/nextcloud.yml` | | `nextcloud_postgres_password` | `changeme` | same | | `nextcloud_s3_key` / `nextcloud_s3_secret` | `changeme` / `changeme` | same | | `garage_webui_password` | `admin` | `host_vars/storage/garage.yml` | | `garage_rpc_secret` | `0123…cdef` (64-hex constant) | same | | `garage_admin_token` | identical to `rpc_secret` | same | | `garage_metrics_token` | identical to `rpc_secret` | same | > **Convention:** every value listed above **must** have a Bao lookup > in `demo-*/host_vars/.../...yml` before the inventory is considered > deploy-ready. ## Threat boundaries (current demo state) | Boundary | Status | Notes | |---|---|---| | DMZ ↔ Backend (172.16.9 ↔ 172.16.19) | **Plaintext HTTP** | Auth bearers, OIDC codes, session cookies travel unencrypted. Fine for demo; for prod use mTLS or a WireGuard overlay. | | Host firewall | **missing** | The `base` role does not install UFW/nftables. Segmentation relies on the hypervisor/VLAN. | | SSH | `ansible_user: root` | No bastion, no jump host. Key distribution out-of-band. | | Authentik SPOF | **accepted** | IdP and SP services share the same host (`application`). An Authentik outage means a login outage including the LDAP outpost. No break-glass path. | | ACME TSIG key | Bao lookup (in Ansible), **plaintext in [`knot.conf`](https://git.digitalboard.ch/Digitalboard/dns-zones/src/branch/main/knot/knot.conf)** on `ns1` side | One TSIG key per demo tenant, scoped via Knot ACL `update-owner-name` to the tenant's ACME sub-tree. Rotation is manual and must be done on both sides simultaneously (Bao + `knot.conf` + `knotc zone-reload`). | | Backup / DR | **out of scope** | Garage `replication_factor: 1` (default), no Postgres backup job, no Bao snapshot cron. | ## To adapt for production, add - Host firewall (extend the `base` role or add a dedicated `firewall` role). - mTLS or WireGuard between DMZ and backend. - Authentik on a separate host with a recovery admin token. - Bao policies per inventory mount (read-only for the deploy token, write-only for the bootstrap job). - Backup cron for Postgres + Garage + Bao. - SSH bastion + key rotation.