What the AWS side of Delegus enforces, as built by infra/. This is the companion to docs/: that document maps spec threats to protocol and service controls; this one states the controls that live in the accounts, the network, and the key store. Everything here is Terraform in infra/ and can be re-derived from it.
Account structure#
- One AWS Organization. The management account holds only Terraform state, the organization CloudTrail, and cost budgets; it runs no workload.
- Two workload accounts,
delegus-devanddelegus-prod, under aworkloadsorganizational unit. Nothing is shared between them: separate VPCs, keys, databases, evidence buckets, and deploy roles. A compromise of dev reaches nothing in prod. - Service control policies on the OU deny, even to an account administrator: leaving the organization; stopping or deleting CloudTrail; scheduling deletion of, or disabling, a production signing key; deleting a production evidence bucket or bypassing its retention (S3 itself refuses to suspend versioning on an Object Lock bucket).
- Continuous control evidence in production: AWS Config records every resource change and evaluates managed rules, Security Hub scores the account against AWS Foundational Security Best Practices, GuardDuty watches for threats; high and critical findings page the on-call topic. Any lifecycle, alias or policy call on a signing key, and any policy, Object Lock, versioning or deletion call on the evidence bucket, pages the same topic within seconds whether or not the call was denied, and is exported as a published transparency record.
- Operators reach the workload accounts only by assuming a role from the management account; the CLI signs in with short-lived console credentials, never long-lived access keys. MFA is required on the root user and on the administrator user.
Signing keys#
- Receipt and status-list signing keys are Ed25519 keys inside AWS KMS (
ECC_,NIST_ EDWARDS25519 SIGN_VERIFY). The private key material never leaves the HSM; the API callskms:Signper receipt and reads the public key once at startup. - Keys are addressed by purpose and generation (
receipt-1,receipt-2,status-1). Rotation adds a generation and flips the active one; retired generations stay enabled and published in the DID document so every receipt ever issued keeps verifying. Nothing deletes a key. - Only the API task role may sign, and only with the keys of its own environment. Development keys are published under
did:web:dev., production keys underdelegus. ai did:web:delegus.; the two sets never meet.ai
Evidence store#
- One S3 bucket per environment with Object Lock. Production uses COMPLIANCE mode with a seven-year default retention: no principal, including the account root, can shorten it or delete a locked version. Development uses GOVERNANCE mode with one-day retention so it can be cleaned up.
- Versioned, encrypted with a dedicated rotating KMS key, private, and policy-locked: TLS only, and any upload naming a different encryption key is refused. The API writes objects addressed by SHA-256 with a conditional PUT and never deletes.
Network and edge#
- Public entry is a single Application Load Balancer with an ACM certificate; TLS 1.2 and 1.3 only, HTTP redirected to HTTPS. API tasks, the database, and Redis live in private subnets with no public addresses; security groups allow the database and Redis to accept connections only from the API tasks.
- AWS WAF in front of the load balancer: a per-source-IP rate limit, the AWS IP-reputation list, and the known-bad-inputs rule group. Blocked and sampled requests are logged.
- The database enforces TLS (
rds.force_ssl) and the API verifies its certificate against the Amazon RDS CA. Redis connections use TLS.
Secrets and deployments#
- The database password is generated and rotated by RDS and read from Secrets Manager at task start. The admin token is generated at apply time as an ephemeral value written through a write-only path, so it never appears in Terraform state or plan output; rotating it rolls every task.
- Images are built by GitHub Actions and pushed to a private ECR repository with scanning on push. The deploy role is assumed through GitHub OIDC, is restricted to the repository's
devorprodenvironment, and can only push the image and roll the service. Production deploys require a reviewer on the GitHub environment. There are no long-lived cloud credentials in CI.
Logging and alerting#
- An organization-wide CloudTrail records every API call in every account, all regions, with log-file validation, into a private bucket retained for 400 days.
- The API writes structured JSON logs to CloudWatch. Alarms notify an SNS topic on load-balancer errors, absence of healthy targets, tasks below the desired count, database and Redis pressure, API startup failures,
SERVICE_denials, and unhandled errors. Monthly cost budgets alert at 80% and 100% of a threshold per account.UNAVAILABLE
What is deliberately not in place yet#
- No Terraform apply from CI: applies run from an operator workstation after a plan is read. Terraform CI with plan-on-PR and a second approver is planned.
- No AWS Config or Security Hub yet; planned for the production account.
- Single region (us-east-1). A second region is a repeat of the same modules.