Admin Login

AWS ECS Deployment Process

💡Find out how to set up a Production Institutional Vault on your own.

The AWS deployment of the self-installed Institutional Vault uses separate AWS KMS policies and Secrets Manager instances for each Policy Node quorum member. Policy Nodes run inside AWS Nitro enclaves during execution so sensitive in-memory data stays isolated. No single party should have access to multiple master key shards.

Roles and Responsibilities

Assign team members before you begin. Multi-account installs split Policy Node KMS keys across accounts.

RolesResponsibilities
Infrastructure adminManages wallet infrastructure in the wallet AWS account
Policy Node adminManages one Policy Node partition and its KMS key (one admin per Policy Node account in the recommended layout)

In the recommended three-account layout:

ActorRolesResponsibilities
Actor AInfrastructure and Policy Node 0 adminWallet infrastructure and Policy Node 0 KMS key
Actor BPolicy Node 1 adminPolicy Node 1 KMS key
Actor CPolicy Node 2 adminPolicy Node 2 KMS key

Summary of Steps Per Role

RolesSteps performed
Infrastructure admin1–11, 13–17
Policy Node admins1–7, 9 (baseline only in their account), 10 (their Policy Node long-lived stack), 12 (their partition secrets)

Prerequisites

  1. AWS experience and comfort with shell scripts and make.
  2. A local install host with Docker, make, AWS CLI, and cosign (recommended for image verification).
  3. Separate AWS credentials per account. Do not use the AWS root user. Follow AWS root user best practices.
  4. An OIDC identity provider for the wallet and Approver App (Auth0, Okta, Azure Entra ID, or equivalent). See Configuring Okta for Okta-specific steps.
  5. A DNS hosted zone for the wallet (for example wallet.<companydomain.com>). The installer creates records in this zone. OIDC redirect URIs must match the deployed hostnames.
  6. AWS account IDs authorized to pull from the Blockdaemon delivery ECR (Blockdaemon configures this from your intake form).
  7. Emergency Recovery Secret (ERS) public key. See Step 2.
  8. Blockdaemon delivery artifacts: wallet release tag, deployer version, Policy Node / enclave tag (MPA_IMAGE_TAG), and API credentials. Blockdaemon sends these through a secure channel if they were not collected on your intake form.
  9. Blockdaemon API key with Native API, Blocks, Events, Transactions, Fee Estimation, Balances for Wallet and UTXOs, and Historical Token Price. Confirm event streaming is enabled for your organization.
  10. Optional integrations:
  11. Chainalysis (https://www.chainalysis.com/) if you use transaction risk screening.

Recommended Wallet Architecture

Review the architecture before you deploy.

Makefile Variables

Set these as environment variables (recommended) or edit defaults at the top of the Makefile Blockdaemon delivers in your installer bundle.

VariablePurposeExample
DEPLOYER_VERSIONWallet deployer container tagv3.4.0
MPA_IMAGE_TAGPolicy Node / Nitro EIF S3 prefix (enclave/<tag>/)v8.26.5
CUSTOMER_SHARED_SEGMENTWallet release tag for the shared S3 bundlev3.4.0
NAMESPACEDeployment namespace (resource naming)acme-custody
ENV_PREFIXEnvironment name and DNS prefixtestnet
AWS_REGIONTarget AWS Regionus-east-1
BACKEND_API_PATHWallet API base URL (frontend and bootstrap)https://api.testnet.wallet.example.com

Run make help from the bundle directory for the full list.

Example exports:

export DEPLOYER_VERSION=<deployer-version>
export MPA_IMAGE_TAG=<policy-node-enclave-tag>
export CUSTOMER_SHARED_SEGMENT=<wallet-release-tag>
export NAMESPACE=<namespace>
export ENV_PREFIX=<environment-name>
export AWS_REGION=<aws-region>
export BACKEND_API_PATH=https://api.<environment-name>.wallet.<company-domain>

Step 1: Create Local Installation Environment

All infrastructure and Policy Node admins configure a local host with:

Configure AWS credentials for the account you will deploy into. For AWS SSO profiles, set AWS_PROFILE and use LOCAL_AWS_PROFILE_MODE=true if your team documents that convention.

Step 2: Generate Emergency Recovery Secret

Generate the ERS key pair before install. Follow Create ERS Key for key generation, ceremony guidance, and how to supply ers_public_key in customer-secrets.yml during Step 12.

📘

Note

Skip this step if you already completed your ERS key ceremony.

Step 3: Receive Blockdaemon Delivery Artifacts

Blockdaemon grants ECR and S3 access and sends:

  • Target wallet release tag (CUSTOMER_SHARED_SEGMENT)
  • Deployer version (DEPLOYER_VERSION)
  • Policy Node / enclave tag (MPA_IMAGE_TAG) when it differs from the wallet tag
  • API credentials and any delivery-specific notes
📘

Note

Skip this step if you already have current delivery values from a prior engagement.

Step 4: Authenticate to the Institutional Vault Registry and Validate Images

All admins authenticate to the Blockdaemon ECR registry:

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin \
638663786504.dkr.ecr.us-east-1.amazonaws.com

Optionally verify the deployer image with cosign (set DEPLOYER_VERSION from Step 3):

export DEPLOYER_VERSION=<deployer-version>
BLOCKDAEMON_SIGNING_AUTHORITY="-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfJLNcMpG3m8EOswCU7cqzWBsHSfY
+rt4HRvbPWAqadeYxIhhBWXjWDiRk4SAa2XXhZVi7IEO7TMaJcuFyHvoBQ==
-----END PUBLIC KEY-----" \
cosign verify --key env://BLOCKDAEMON_SIGNING_AUTHORITY \
638663786504.dkr.ecr.us-east-1.amazonaws.com/blockdaemon/wallet-deployer/aws:${DEPLOYER_VERSION}

Step 5: Download the Installer Bundle

All admins download the shared installer bundle from S3 into a dedicated working directory. The bundle includes the Makefile, customer-config.yml template, tenant-setup.json, helper scripts, and cold-wallet templates.

The bundle path is s3://638663786504-prod-mpa-deployment-customer-artifacts/customer/shared/<wallet-release-tag>/.

Copy the Makefile from S3, then sync the rest of the bundle with make:

export CUSTOMER_SHARED_SEGMENT=<wallet-release-tag>
aws s3 cp s3://638663786504-prod-mpa-deployment-customer-artifacts/customer/shared/${CUSTOMER_SHARED_SEGMENT}/Makefile .
make pull-customer-assets
📘

Note

By default, pull-customer-assets does not overwrite a local Makefile. To refresh the Makefile from S3, run PULL_SYNC_MAKEFILE=1 make pull-customer-assets after backing up local edits.

Step 6: Configure Makefile Variables

All admins set the variables in Makefile Variables for the environment they deploy. ENV_PREFIX is the environment name (Blockdaemon recommends testnet and mainnet) and DNS prefix. NAMESPACE must match the value you will use in customer-config.yml.

Step 7: Generate Deployment Configuration

All admins complete local configuration before infrastructure deploy.

  1. Pull the deployer image:
make pull-deployer
  1. Edit customer-config.yml with your namespace, AWS accounts, hosted zones, admin users, optional Canton settings, and resource tags. See customer-config.yml Reference.
  2. Generate deployment assets:
make generate-customer-assets

tenant-setup.json

Edit tenant-setup.json in the installer bundle before bootstrap (Step 16). This file is the request body for POST /api/tenants/default/setup. It seeds initial Vault users, the owner group, master keys, and registered chains. It does not define transaction restrictions or admin policies.

FieldPurpose
UsersInitial Vault users (ID is email, Name is display name)
GroupOwner group name (for example owner)
MasterKeysAndAccountsHot master keys and account names
Assets.CAIP2sCAIP-2 chain identifiers to register at bootstrap

Configure policies after bootstrap in the Vault UI or through supported policy APIs.

📘

Note

After the first install, you may edit bd-wallet.yml directly for some changes. Regenerate from customer-config.yml when you change namespace, accounts, or hosted zones.

Step 8: Optional Cold Wallet Bundle

Infrastructure admin only, when cold wallet is in scope:

make generate-cold-wallet-bundle

This produces cold-wallet.tar.gz for air-gapped Policy Node operations. Skip when you deploy hot quorum only.

Step 9: Deploy Stage 1 (Baseline and Long-Lived Infrastructure)

Confirm ENV_PREFIX and NAMESPACE match bd-wallet.yml, then deploy long-lived infrastructure.

Infrastructure admin (wallet account)

Either run the stage wrapper:

make deploy-stage-1

Or run the same steps individually:

make deploy-baseline
make deploy-service-images
make generate-conf-files
make fetch-enclave-artifacts
make deploy-wallet-long-lived
make deploy-all-policy-nodes-long-lived

deploy-stage-1 creates baseline CDK resources, populates customer ECR with service images, generates component config files, downloads Nitro enclave.eif / pcr.json for MPA_IMAGE_TAG, and deploys wallet and Policy Node long-lived stacks in the wallet account.

📘

Note

Do not delete long-lived stack resources unless you are decommissioning the environment.

Policy Node admins (separate accounts)

In each Policy Node account:

make deploy-baseline
make fetch-enclave-artifacts
make deploy-policy-node0-long-lived   # or node1 / node2 for that admin

Policy Node admins do not run deploy-service-images or deploy-wallet-long-lived.

Step 10: Deploy Policy Node KMS Keys (Multi-Account)

When Policy Node KMS keys live in accounts other than the wallet account, each Policy Node admin deploys only their partition (if not already done in Step 9):

make deploy-policy-node0-long-lived
make deploy-policy-node1-long-lived
make deploy-policy-node2-long-lived

Run only the target matching the account you control.

Step 11: Verify Deployer Image

If any admin skipped Step 7.1, pull the deployer before secrets or Stage 2:

make pull-deployer

Step 12: Generate and Populate Secrets

The Encryptor Master Password encrypts each Policy Node database that holds a master key share. One password exists per Policy Node partition. The install tooling encrypts and stores values in AWS Secrets Manager.

  1. Infrastructure admin generates the secrets template:
make generate-secret-file
  1. Infrastructure admin edits customer-secrets.yml with:
  • ubiquity_org_username and ubiquity_auth_token (Blockdaemon Workspace and API key)
  • OIDC values under the auth0 block (AUDIENCE, ISSUER, CLIENT_ID_SPA, CLIENT_ID_NATIVE) for Auth0-shaped configs; use the keys your IdP mapping expects
  • ers_public_key (see Create ERS Key)
  • broker-root-ca and broker-root-ca-key (NATS mTLS root; use YAML \| literal blocks with PEM newlines)
  • Optional: chainalysis-user, chainalysis-token, canton-client-id, canton-client-secret, custom chain RPC URLs Do not commit customer-secrets.yml.
  1. Infrastructure admin:
make populate-secrets-wallet
  1. Policy Node 0 admin:
make populate-secrets-policy-node0
  1. Policy Node 1 admin:
make populate-secrets-policy-node1
  1. Policy Node 2 admin:
make populate-secrets-policy-node2
🚧

Warning

Re-running populate-secrets-wallet on a live environment overwrites most wallet-partition secrets in AWS Secrets Manager. It does not replace Policy Node Encryptor Master Passwords (those belong to the policy-node populate targets). Avoid blind re-runs: db-info and webhook-token values are regenerated and can break a running wallet. Re-run populate only when you intend to rotate the secrets you changed in customer-secrets.yml.

Step 13: Deploy Stage 2 (Wallet Runtime and Policy Nodes)

After secrets are populated, infrastructure admin deploys runtime services on ECS and Nitro hosts.

Either:

make deploy-stage-2

Or individually:

make generate-fe-env
make deploy-wallet
make deploy-nitro-nodes
make start-wallet
  • **generate-fe-env** requires BACKEND_API_PATH. It builds env-config.js and packages frontend.zip.
  • **deploy-wallet** deploys ECS task definitions with wallet count 0 (services defined, wallet not started).
  • **deploy-nitro-nodes** deploys Nitro EC2 instances for all three Policy Nodes.
  • **start-wallet** sets WalletServiceCount=1 and starts the wallet service.
🚧

Warning

After go-live, do not change the public API URL without a planned migration. Event streaming and integrations depend on a stable endpoint.

If CDK fails pulling the AWS SAM CLI image from public.ecr.aws, run make ecr-public-login on the host and retry.

Step 14: Apply Configuration Changes After Install

When you change bd-wallet.yml (or regenerate it) on an already running wallet:

make generate-conf-files
make deploy-wallet

Add make deploy-nitro-nodes when Policy Node configuration changed. Add make generate-fe-env when BACKEND_API_PATH changed.

Use make start-wallet only if the wallet service is still at desired count 0. Do not use start-wallet as a substitute for deploy-wallet when applying config.

For secret value changes, edit customer-secrets.yml and run the appropriate populate-secrets-* target for the partition you changed, then redeploy affected services.

Step 15: Optional RDS Snapshot Before Upgrades

Before major upgrades:

export RDS_DB_INSTANCE_IDENTIFIER=<your-cluster-id>
make backup-rds-snapshot

See AWS Wallet Upgrade.

Step 16: Populate Initial Tenant State

After the wallet is healthy, infrastructure admin seeds users, groups, master keys, and registered chains from tenant-setup.json (see Step 7).

The wallet creates a bootstrap Admin API key automatically on first start (Step 13) and stores it in AWS Secrets Manager. Retrieve it before bootstrap (replace NAMESPACE and ENV_PREFIX with your Makefile values, or substitute your namespace and environment name):

export WALLET_API_KEY=$(aws secretsmanager get-secret-value \
  --region "${AWS_REGION}" \
  --secret-id "bd-wallet.${NAMESPACE}.${ENV_PREFIX}.bootstrap-key" \
  --query SecretString --output text)
export BACKEND_API_PATH=https://api.<environment-name>.wallet.<company-domain>
make bootstrap-policies-and-users

This calls POST /api/tenants/default/setup as the [email protected] system user. It is one-shot: a second successful run returns an "already populated" response. Configure transaction restrictions and admin policies afterward in the Vault UI or through supported policy APIs.

📘

Note

Override the JSON path with TENANT_SETUP_JSON=/path/to/file.json when needed.

Step 17: Backup the Wallet Master Private Key

After first login and Approver App pairing, approve master key backup in the Approver App. Store backup material separately from the live system.

See Back Up Master Key.