Secret Delivery Pattern
How partition-scoped operational secrets sourced from 1Password are delivered into AWS Secrets Manager at deploy time, where they then become available to:
- CloudFormation Custom Resource Lambdas at deploy time (e.g., Postmark Sender Signature registration).
- Runtime workloads via External Secrets Operator (ESO) in the partition’s Kubernetes cluster.
For where the source-of-truth secrets are stored in 1Password (vault layout, scoping rules), see secrets-vault.md.
The pattern
Section titled “The pattern”┌─────────────────┐ op read ┌───────────┐ --parameters ┌───────────────────────┐│ Arda-{Env}OAM │ ───────────────► │ amm.sh │ ─────────────────►│ CDK / CFN template ││ (1Password) │ │ │ (NoEcho) │ (CfnParameter + │└─────────────────┘ └───────────┘ │ SecretValue.cfn…) │ └──────────┬────────────┘ │ ▼ ┌─────────────────────┐ │ AWS Secrets Manager │ │ (per-partition SM │ │ secret with stable │ │ ARN export) │ └──────────┬──────────┘ │ ┌────────────────────────┴───────────────┐ ▼ ▼ ┌─────────────────┐ ┌──────────────────────┐ │ CR Lambda at │ │ ESO ExternalSecret │ │ deploy time │ │ → Kubernetes Secret │ │ (GetSecretValue)│ │ → pod env / mount │ └─────────────────┘ └──────────────────────┘Step-by-step
Section titled “Step-by-step”- Source of truth in 1Password. The secret value lives in the partition’s
Arda-{Env}OAMvault (per the Secrets Vault convention). Same item titled identically across all four partition vaults — values may differ per partition but the schema doesn’t. - Operator reads via
amm.sh.amm.sh(or a callee) runsop read 'op://Arda-{Env}OAM/<item>/<field>'to capture the value in a shell variable. In GitHub Actions,echo "::add-mask::$value"is called immediately after the read to prevent accidental log exposure —op-sourced values are not auto-masked by GHA (only${{ secrets.* }}are). - Pass to CloudFormation / CDK as a
NoEchoparameter.amm.shinvokes either:aws cloudformation deploy --parameter-overrides "<Param>=$value"for raw-CFN stacks (e.g.,partitionSecrets.cfn.yaml), orcdk deploy --parameters "<Param>=$value"for CDK stacks. The CDK side declares aCfnParameterwithnoEcho: trueand creates the SM secret viaSecretValue.cfnParameter(thatParam).
- CloudFormation creates the SM secret.
Type: AWS::SecretsManager::SecretwithSecretString: !Ref <Param>(raw CFN) or the CDK-synthesized equivalent.NoEchokeeps the value out ofDescribeStacks, change-sets, and event logs.RemovalPolicy.RETAINdefends against accidental destroy. - Stack exports the SM secret ARN. Downstream stacks (CR Lambdas, ESO
ExternalSecretmanifests) consume the secret by ARN throughFn::ImportValue. - Consumers read via
GetSecretValue. CR Lambdas at deploy time; ESO at runtime (projecting into a Kubernetes Secret for the pod). The same SM secret can serve both consumer classes.
Rotation
Section titled “Rotation”Source-of-truth-first rotation: update the 1Password item, then re-run amm.sh for the affected partition. The next cdk deploy / aws cloudformation deploy passes the new value through the NoEcho parameter and CloudFormation updates the SM secret’s SecretString. Direct aws secretsmanager put-secret-value writes will be reverted on the next deploy — this is intentional, keeping 1Password as the unambiguous source of truth.
Worked examples
Section titled “Worked examples”partitionSecrets.cfn.yaml— the canonical raw-CFN instance of the pattern. Six secrets (ArdaApiKey,ArdaSignupKey,HubspotClientKey,HubspotPAT,PylonWidgetKey,AmazonCreatorsApi) all follow this shape today. Seeinfrastructure/src/main/cfn/partitionSecrets.cfn.yamland theSecretsstep ininfrastructure/amm.sh.- Phase 4
partition-emailstack — Postmark account token — the canonical CDK instance.postmarkCredentialOpReference(partition)inplatform/postmark-service.tsreturns theop://reference;amm.shreads it; thepartition-emailstack declares aNoEchoCfnParameterand creates the SM secret viaSecretValue.cfnParameter().
When to use this pattern vs alternatives
Section titled “When to use this pattern vs alternatives”- Use this pattern when the secret is sourced externally (third-party API key, vendor token, manually-issued credential) and needs to land in AWS Secrets Manager.
- Do not use this pattern when:
- The secret is generated by AWS itself (e.g., RDS-generated master passwords) — use the SM-native
generateSecretStringinstead. - The secret is generated by CDK at synth time — use
generateSecretStringdirectly; no 1Password round-trip needed. - The secret never needs to land in AWS (e.g., a CI-only token consumed by GitHub Actions) — use
${{ secrets.* }}directly.
- The secret is generated by AWS itself (e.g., RDS-generated master passwords) — use the SM-native
Related
Section titled “Related”- Secrets Vault — 1Password vault layout (the source-of-truth side of this pattern).
amm.sh— the operator entry point that orchestrates theop→ CFN call.partitionSecrets.cfn.yaml— the canonical worked example today.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved