A reusable, audited reference for deploying a Splice/Canton validator on AWS. Terraform-managed, parameterized for DevNet → TestNet → MainNet, designed for teams custodying real value via external party signing.
For teams adopting this repo: the Terraform modules and AWS architecture are application-agnostic. Application-specific guidance (e.g., "this party needs external KMS signing because of unilateral fund-moving capability") is flagged inline with
APPLICATION-SPECIFICcallouts in the design doc. Audit your own Daml model and substitute accordingly. Fork, fill in your tfvars, and run.
The full deployment is broken into phases. Each phase leaves the world in a coherent state — pause between phases for review, security drills, and DR rehearsals.
# Phase 1 — create state backend, GitHub OIDC trust, plan-on-PR role
bash terraform/bootstrap/bootstrap.sh us-east-1 <org>/canton-validator-setup
# Hand the plan-on-PR role ARN to GitHub
ROLE_ARN="$(cd terraform/bootstrap && terraform output -raw github_actions_role_arn)"
gh variable set AWS_GH_ACTIONS_ROLE_ARN --body "$ROLE_ARN" --repo <org>/canton-validator-setupWalkthrough of what bootstrap does and what each AWS resource it creates is for: terraform/bootstrap/README.md.
bash terraform/init-env.sh devnet # do testnet/mainnet later when neededConfigures the Terraform working directory at terraform/envs/devnet/ to point at the S3 backend created by bootstrap. No AWS resources are created — just local working-dir setup.
cd terraform/envs/devnet
terraform plan -var-file=terraform.tfvars
terraform apply -var-file=terraform.tfvars| Phase | Focus |
|---|---|
| 0 | Directory scaffolding & repo conventions |
| 0.5 | Resolved prerequisites (decisions, not work) |
| 1 | Terraform state backend + bootstrap script + GitHub Actions plan-on-PR |
| 2 | Networking (VPC, subnets, NAT, ACM cert with externally-managed DNS) |
| 3 | Security baseline (KMS, IAM, Secrets Manager, CloudTrail, VPC endpoints, secret rotation) |
| 4 | S3 backup bucket + AWS Backup with vault lock |
| 5 | Validator host module (EC2, ALB, ASG, persistent data EBS) |
| 6 | User-data scripts (bootstrap, mount, secrets, hash library, party allocation, DAR upload) |
| 7 | Keycloak provisioning (realm, PQS read-only role, probe party) |
| 8 | Backup tooling (ordered backup + KMS-signed manifest, restore split, participant pruning) |
| 9 | Observability (Prom/Grafana, alarms, canary alarm on host signing attempts, synthetic probe) |
| 10 | Operations helpers (Makefile, deploy wrapper) |
| 11 | Runbooks (10 total) |
| 12 | DevNet validation, DR drills, attacker simulation |
| 12.5 | TestNet bake (production-shape, 14-day integration + Splice upgrade rehearsal) |
| 13 | MainNet preparation |
Full plan: docs/plans/2026-05-05-validator-production-implementation.md.
You already have:
- An AWS account with admin access (the bootstrap module creates IAM roles, KMS keys, S3 buckets)
- A registered domain with DNS hosting at any provider (Route 53, Cloudflare, registrar's DNS — all work)
- Sponsor SV onboarding for whichever Splice network you're targeting:
- DevNet: self-serve via the sponsor's onboarding API (no human in the loop)
- TestNet / MainNet: out-of-band onboarding from a Super Validator (provides a 48h-valid onboarding secret)
- A Daml application to host (or you're running a vanilla validator with no application logic)
- Local tooling: Terraform ≥ 1.6 (native arm64 on Apple Silicon — Rosetta x86 builds time out during plugin handshake), AWS CLI v2,
jq,shellcheck, GitHub CLI (gh)
.
├── terraform/ Terraform modules + per-env stacks
│ ├── bootstrap/ One-time state backend setup (S3 + DynamoDB + OIDC role)
│ ├── modules/ Reusable modules: networking, security, validator-host, ...
│ ├── envs/ Per-env wiring: devnet, testnet, mainnet
│ ├── shared/ Shared backend.tf template
│ └── init-env.sh Per-env terraform-init wrapper
├── user-data/ EC2 cloud-init bootstrap scripts
├── compose-overrides/ docker-compose.override.yaml for prod patches
├── keycloak/ Realm template + provisioning
├── backup/ Ordered backup, restore, systemd timers
├── operations/ Helper scripts (deploy, rotate, probe, allocate-party, ...)
├── runbooks/ Markdown runbooks for ops scenarios
├── docs/plans/ Design + implementation + audit findings
├── .github/workflows/ Plan-on-PR CI
└── old-setup/ Legacy bash-script flow (kept as POC reference)
├── scripts/ setup.sh, proxy.sh, auth.sh, pqs.sh, monitoring.sh
├── monitoring/ Old Prometheus/Grafana stack
└── docs/ DNS.md, PQS.md, DAR.md, MONITORING.md
runbooks/README.md— operational entry point. Index of runbooks + ops scripts, typical operator flows, where SM secrets live.terraform/bootstrap/README.md— bootstrap walkthrough, resource-by-resource explanation, setup flowdocs/architecture-overview.md— backup model, IAM roles, KMS keys, restore flow, key auth pathsdocs/plans/2026-05-05-validator-production-design.md— architectural decisions and why they were madedocs/plans/2026-05-05-validator-production-implementation.md— phased, executable plan (current state of work)docs/plans/2026-05-05-validator-audit-findings.md— three independent audit reports (SEAL framework, Canton/Daml correctness, plan review)
The implementation plan's Phase 0.5 (Resolved prerequisites) captures decisions that change downstream phases. Read it before Phase 1.
Rough monthly idle costs, before ledger traffic:
| Env | Cost | Drivers |
|---|---|---|
| DevNet | ~$200/mo | 2× NAT Gateway, t3.large, AWS Backup + S3, ~5 KMS keys, CloudWatch |
| TestNet | ~$500/mo | MainNet-shaped (m6i.xlarge, separate Keycloak host) but no cross-region replication, shorter retention |
| MainNet | ~$600/mo + traffic | + cross-region replication, longer retention, more KMS Sign calls, plus synchronizer traffic in CC |
S3 Object Lock in Compliance mode is irrevocable for the retention window. Use 1-day retention or Governance mode on DevNet to allow tear-down during testing; Compliance + 30d only on MainNet.
Before the Terraform-based flow, the repo shipped guided bash scripts (old-setup/scripts/setup.sh, proxy.sh, auth.sh, pqs.sh, monitoring.sh) that deployed a single-host validator on Amazon Linux 2023. Those still work and remain in old-setup/ as a POC reference, but are not the recommended path for production. New work goes into the Terraform stack at the top level.
Docs for the bash flow: old-setup/docs/ — DNS, PQS, DAR upload, monitoring.