BYOC deployment — AWS
Procedure for provisioning the platform into a customer's AWS
account. Every apply runs through the existing controller gate
(plan → OPA → plan-binding → four-eyes approval → apply); workspaces
named customer-<slug>-<env> are matched by the authz matrix to the
full prod tier (hard-mandatory policy, distinct approver, step-up MFA).
Feature flag: byoc_deployments_enabled (monolith) gates the deployment
record + spec routes.
Prerequisites
Customer side (send them this section):
- Create IAM role
AlphaSwarmDeployRolein the target account with a trust policy allowing our ops account to assume it, conditioned on an ExternalId (we supply it; it is the customer id — cross-reference the pattern in multi-account-rollout). - Attach the deployment permission set (VPC/EKS-or-ECS/RDS/S3/KMS/ECR as
per the module README:
terraform/modules/customer_account_aws/README.md). - Tell us the 12-digit account id, target region, and the role ARN.
Our side:
- Customer onboarded with an active
enterprisecontract (byoc_deployments: trueresolved — see enterprise-customer-onboarding). - The external id stored in the secrets platform; note its vault path
(never the raw value) — e.g.
secret/customers/<slug>/external-id. - State backend exists in the ops account: S3 bucket
alphaswarm-customer-tfstate(+ DynamoDB lock tablealphaswarm-customer-tf-lock). - You hold
manage:infrastructure+terraform:admin; a second approver is available for the apply.
Steps
- Create the deployment record — customer detail page → BYOC
deployments → New deployment: name, env suffix (
prod,staging), AWS account id, region, deploy-role ARN. This derives the workspace namecustomer-<org-slug>-<suffix>; then PATCH the record'sexternal_id_vault_pathto the vault path from prerequisites. - (First lease) issue the deployment's license lease with
license_deployment_idmatching the record — see license-issuance-and-revocation. The terraform module wiresALPHASWARM_LICENSE_*+license_enforcement_enabled=trueinto the workloads. - Render the spec — Render spec on the deployment row. This
snapshots a hash-locked
TerraformStackSpec(registry rule 43) and upserts theterraform_workspacesrow (slug = workspace name, state in the ops-account S3 backend). Status:draft → planning. - Plan — Plan / apply → deep-links to the Terraform page; run the
plan on the customer workspace. The OPA customer gate enforces:
provider must
assume_roleinto the declared account, only allowlisted providers, no unreviewed stateful deletes. - Review + approve — the plan binding pins the exact tfplan; the second operator approves (four-eyes; step-up). Apply executes the bound plan only.
- Sync status — Sync on the deployment row folds the run outcome
into the record (
awaiting_approval → applying → active).
Post-action verification
- Deployment row
activewith the apply-run id linked. - Customer-side smoke: platform health endpoint answers; a gated route
(e.g. terraform surface) returns 200 with an entitled lease and no
X-AlphaSwarm-License-Statusheader (i.e. leaseactive, not grace). - The KB silo exists in the customer account (RDS/S3 encrypted with the per-tenant KMS key) — module outputs list the endpoints.
- Terraform state landed at
s3://alphaswarm-customer-tfstate/customers/<slug>/<env>.tfstate.
Escalation
- OPA
denyon plan → read the finding; assume_role/provider findings mean the rendered spec or role setup is wrong — fix and re-render; never downgrade the workspace's policy tier. Assumed role landed in account …precondition failure → the role ARN points at the wrong account; verify with the customer.- Apply half-failed → terraform state is authoritative; re-plan and re-apply through the same gate (see byoc-upgrade-and-rollback for rollback).