Skip to content

Phase 4 -- Runtime Platform Updates -- Exports

Cross-phase contracts that Phase 4 produces and that downstream consumers (Phase 5b, future runtime-platform additions, the operations Helm chart, drift workflows) read. Each export is named, typed, and pinned to a producer.

The principal consumer of Phase 4’s CFN exports is the operations Helm chart (non-CDK), which is why every CFN export uses the -API- marker per cdk-infrastructure.md § Export naming. Phase 4’s resource names continue to use the -I- marker (intra-partition AWS scope; per the partitionSecrets.cfn.yaml convention) — that marker is independent of the CFN export-name marker.

Per partition (4 active partitions × 6 exports = 24 CFN exports total; kyle excluded). Each export is published by the ${infrastructure}-${partition}-Email CloudFormation stack.

Export nameValue type / shapeProducerPrimary consumer
${publishingPrefix}-API-PartitionMailZoneIdRoute53 hosted zone ID (Z0123…)PartitionEmailStack per partitionPhase 5b operations Helm chart (for route53:ChangeResourceRecordSets HostedZoneId parameter) + drift workflow
${publishingPrefix}-API-PartitionMailZoneNameCanonical zone name ({partition}.ardamails.com)PartitionEmailStack per partitionPhase 5b for SDK ListHostedZonesByName and record-set FQDN composition; drift workflow
${publishingPrefix}-API-EmailPostmarkAccountTokenArnSM secret ARN (arn:aws:secretsmanager:…:secret:${fqn}-I-EmailPostmarkAccountToken-XXXXXX)PartitionEmailStack per partition (Postmark account-token SM secret)Phase 5b operations Helm chart ESO ExternalSecret (mounts the token at runtime for the per-tenant server provisioning)
${publishingPrefix}-API-EmailEncryptionKeyArnSM secret ARN (arn:aws:secretsmanager:…:secret:${fqn}-I-EmailEncryptionKey-XXXXXX)PartitionEmailStack per partition (encryption-key SM secret)Phase 5b operations Helm chart two ESO ExternalSecret mounts (AWSCURRENT + AWSPREVIOUS) — both reference this single ARN with different versionStage selectors
${publishingPrefix}-API-EmailDnsProvisioningRoleArnIAM role ARN (arn:aws:iam::…:role/${roleName})PartitionEmailStack per partition (DNS-records role via generalized AllowCreatingNSRecordsRole)Phase 5b operations component’s STS-AssumeRole credential provider for runtime DNS writes (conditional on DQ-R1-023’s resolution)
${publishingPrefix}-API-EmailEncryptionKeyFallbackRoleArnIAM role ARNPartitionEmailStack per partition (fallback role)Phase 5b operations component’s SecretsManagerClient STS-AssumeRole for the SDK cache-miss fallback path

The operations Helm chart’s values overlay (or amm.sh-driven generation) reads these CFN exports via aws cloudformation list-exports (or describe-stacks --query 'Stacks[0].Outputs') and threads the values into the Helm chart’s values.yaml per release. Concrete wiring is Phase 5b’s specification.md to pin; Phase 4 ships the exports.

The runtime-platform-drift workflow reads the exports the same way to discover what to probe per partition.

2. TypeScript exports from infrastructure/src/main/cdk/stacks/purpose/partition-email.ts

Section titled “2. TypeScript exports from infrastructure/src/main/cdk/stacks/purpose/partition-email.ts”

Follows the canonical three-interface stack pattern documented in ../../../../../technology/cdk-infrastructure.md § Stacks (closest precedent: ImageStorageStack in stacks/purpose/image-storage.ts).

NameKindPurpose
ConfigurationinterfaceDesign-time parameters the consumer (instance config) decides: locator: purpose.Locator (composes infrastructure.id + partition.id), postmarkAccount: postmarkService.AccountReference (the POSTMARK_PROD_ACCOUNT or POSTMARK_NONPROD_ACCOUNT typed ref the partition binds to), dmarcReportingMailbox: string ("dmarc-reports@arda.cards" per pre-design follow-up C2).
Props extends ConfigurationinterfaceAdds runtime injections from the App: postmarkAccountTokenParam: cdk.CfnParameter (the NoEcho parameter declared in apps/Al1x/partition.ts), podRoleArnPattern: string (the ${fqn}-* pattern for the IAM roles’ ArnLike trust condition).
BuiltinterfaceCross-CDK exposures (consumed by sibling stacks if any). Phase 4 has no sibling CDK consumer (Phase 5b consumes via CFN -API- exports, not CDK Built), but Built is populated for codebase consistency: partitionMailZone: r53.IHostedZone, emailEncryptionKeySecret: secretsmanager.ISecret, emailPostmarkAccountTokenSecret: secretsmanager.ISecret, emailDnsProvisioningRole: iam.IRole, emailEncryptionKeyFallbackRole: iam.IRole.
ExportKeystype (string union)CFN export key identifiers: "partitionMailZoneIdAPI" | "partitionMailZoneNameAPI" | "emailPostmarkAccountTokenArnAPI" | "emailEncryptionKeyArnAPI" | "emailDnsProvisioningRoleArnAPI" | "emailEncryptionKeyFallbackRoleArnAPI". Every key suffixed API (the publish() regex enforces alignment with the -API- export-name marker).
ExportDefinitionclass extends stackTypes.ExportDefinitions<ExportKeys>The newer ExportDefinition form (per cdk-infrastructure.md § Export-key pattern; same shape as ImageStorageStack’s).
exportDefinition(publishingPrefix: string)factory functionReturns an ExportDefinition instance keyed to a partition’s publishing prefix.
ExportValuesinterfaceThe resolved (post-readImports) shape of the exports — typed values consumers of the stack import; matches ExportKeys 1:1.
PartitionEmailStackclass extends cdk.StackConstructor signature: constructor(scope: Construct, id: string, props: Props & cdk.StackProps). Static private validateProps(props: Props & cdk.StackProps): Error[] runs purpose.validatePurposeLocator(props.locator) + awsUtil.validateStackProps(props) + domain-specific checks; the constructor throws misc.MultiError on accumulated errors before super(). Composes hosted zone, NS-delegation CR, SPF/DMARC records, DKIM/Return-Path records, both SM secrets, both IAM roles; populates this.built; publishes all six -API- CFN exports. CFN stack name is the literal ${infrastructure}-${partition}-Email passed as the id argument (immutable per § 1.4 of specification.md).

3. TypeScript exports from infrastructure/src/main/cdk/platform/postmark-service.ts

Section titled “3. TypeScript exports from infrastructure/src/main/cdk/platform/postmark-service.ts”
NameKindPurpose
postmarkCredentialOpReference(partition)function(partition: PartitionId): stringReturns op://Arda-{Env}OAM/Postmark/credential for the partition’s bound Env vault. Consumed by amm.sh (via op read); CDK has no 1P dependency.
POSTMARK_PROD_ACCOUNT / POSTMARK_NONPROD_ACCOUNTtyped account references (unchanged from Phase 1)Inherited from Phase 1; consumed by Phase 4’s instance configs to declare each partition’s Postmark account binding.

4. TypeScript exports from infrastructure/src/main/cdk/constructs/oam/allow-creating-{ns,dns}-records-role.ts

Section titled “4. TypeScript exports from infrastructure/src/main/cdk/constructs/oam/allow-creating-{ns,dns}-records-role.ts”

(Phase 4 generalizes the existing construct; the file may also be renamed.)

NameKindPurpose
AllowCreatingNSRecordsRole (or AllowCreatingDnsRecordsRole if renamed)class extends ConstructThe generalized construct. Trust principal is parameterizable: legacy Lambda + OrgID (Phase 2 Root use case; default for backwards compatibility) or account principal + ArnLike (Phase 4 STS-chain use case).
ConfigurationinterfaceGains a new field trustPrincipal: TrustPrincipalConfig — a discriminated union: { kind: "lambdaOrgID"; orgId: string } (legacy default; the Phase 2 Root call site passes this shape) OR { kind: "stsAssumeRole"; account: string; arnLikePattern: string } (Phase 4 form; arnLikePattern is the aws:PrincipalArn ArnLike value, typically arn:aws:iam::<account>:role/<fqn>-*). The existing allowedParentHostedZoneIds?: string[] scope-tightening field is unchanged.
Props extends Configuration / BuiltinterfaceShape unchanged across the generalization.
validatePropsstatic methodNow validates the trustPrincipal discriminated union: each variant’s required fields must be present and shaped correctly. Returns Error[]; the constructor throws misc.MultiError on accumulated errors.

Hard invariant: the Root-account instantiation in root-dns-stack.ts produces byte-identical CloudFormation before and after the generalization (V-IAC-002 enforces this both pre-merge as a CDK Template.fromStack() snapshot test and post-merge as an operator-driven cdk diff against the deployed Root template).

5. TypeScript exports from infrastructure/tools/

Section titled “5. TypeScript exports from infrastructure/tools/”
NameKindPurpose
tools/register-partition-mail-signature.tsTS script with a two-positional-argument CLI shape (<infrastructure> <partition>) and a no-arg usage outputPhase A entry script. Invoked by amm.sh via npx ts-node tools/register-partition-mail-signature.ts <infrastructure> <partition> (per-partition; amm.sh iterates if all was passed). When invoked without arguments it emits a usage block (per § 4 of cdk-infrastructure.md operator-friendly convention; mirrors amm.sh’s usage output). Not a standalone operator-facing CLI (DQ-R1-022).
tools/runtime-platform-drift.tsTS scriptThe drift driver invoked by runtime-platform-drift.yml. Enumerates instances/Alpha001/{prod,demo}.ts + instances/Alpha002/{dev,stage}.ts; probes Postmark + DNS + AWS SM + IAM state; reports drift.
tools/lib/postmark-client.ts (or equivalent)TS module (helpers)Postmark Account API client with retry / backoff and idempotent list-then-create helpers. Consumed by corporate-cli.ts, register-partition-mail-signature.ts, and the drift driver. Final file layout pinned at implementation.
tools/lib/op-resolver.ts (or equivalent)TS module1Password SDK resolution wrapper. Single function resolveOpReference(ref: string): Promise<string>. Consumed by corporate-cli and register-partition-mail-signature.ts.
tools/lib/redact.ts (or equivalent)TS moduleOutput redaction helper for logs and cdk.context.json writes. Consumed by the same set.
tools/lib/drift/*.ts (or equivalent)TS modulesShared drift utilities extracted from corporate-drift.ts per DQ-R1-018: Postmark probe helpers, DNS lookup helpers, report-shape rendering, GitHub-issue creation, cross-seam assertion machinery.

The Phase 4 partition-mail step in amm.sh (invoked per partition) is the operator-facing entry point for partition-mail provisioning. The step is not a standalone CLI — operators invoke amm.sh per its existing partition-selection interface (the implementer aligns with the existing partitionSecrets step’s shape).

Inputs (operator invocation):

./amm.sh [--profile <aws_profile>] [--region <aws_region>] <infrastructure> (<partition>...)
  • Infrastructure name (required positional): Alpha001 (hosts prod + demo) or Alpha002 (hosts dev + stage). SandboxKyle002 is retired (PDEV-438) — amm.sh exits 0 with a notice if invoked with it.
  • Partition name(s) (one or more positional, OR the special token all which amm.sh expands per-infrastructure: Alpha001demo prod, Alpha002dev stage).
  • Optional --profile / --region flags (per the AWS-CLI shape; the script exports them via AWS_PROFILE / AWS_REGION env vars for downstream CDK invocations — note the env-var export happens inside amm.sh, not from the operator’s shell prefix, per workspace memory feedback_aws_profile_flag).
  • AWS SSO session for the partition’s Infrastructure account (Admin-Alpha1 for Alpha001; Alpha002-Admin for Alpha002).
  • 1Password access (operator’s local op CLI signed in to the partition’s Arda-{Env}OAM vault).

Outputs:

  • Partition mail sub-zone live and delegated.
  • Postmark Sender Signature for {partition}.ardamails.com registered and verified.
  • Both partition SM secrets (Postmark token, encryption key) populated.
  • Both partition IAM roles declared.
  • Updated cdk.context.json (committed in the per-partition PR).
  • Operator sign-off row populated in verification.md.

7. CI surfaces from infrastructure/.github/workflows/runtime-platform-drift.yml

Section titled “7. CI surfaces from infrastructure/.github/workflows/runtime-platform-drift.yml”
SurfaceDescription
Daily scheduled runProbes per-partition Postmark + DNS + AWS-SM + IAM state. Fails closed by opening a labelled GitHub issue (drift + runtime-platform).
workflow_dispatch manual triggerOperator-initiated run for verification or post-rollout smoke-test.
Shared utility surface (tools/lib/drift/)Reusable helpers (Postmark probe, DNS lookup, report rendering, GitHub-issue creation) consumed by both runtime-platform-drift and corporate-drift per DQ-R1-018. corporate-drift workflow YAML is not renamed.

8. 1Password vault surface (consumed; not created)

Section titled “8. 1Password vault surface (consumed; not created)”

Phase 4 reads but does not write to the 1Password vaults listed below. The vaults already exist (provisioned during Phase 1 and the Phase-4 prerequisite work).

Per-partition Arda-{Env}OAM vaults — read by the deploy path

Section titled “Per-partition Arda-{Env}OAM vaults — read by the deploy path”

Read by amm.sh (operator-driven) and tools/register-partition-mail-signature.ts (invoked by amm.sh). Resolution goes through postmarkCredentialOpReference(partition) (§ 3).

VaultItemFieldConsumer
Arda-DevOAMPostmarkcredentialamm.sh for dev partition deploy; register-partition-mail-signature.ts for the dev Sender Signature registration on PostmarkNonProd
Arda-StageOAMPostmarkcredentialsame for stage partition (PostmarkNonProd)
Arda-DemoOAMPostmarkcredentialsame for demo partition (PostmarkProd)
Arda-ProdOAMPostmarkcredentialsame for prod partition (PostmarkProd)

Pre-flight: op read "$(postmarkCredentialOpReference <partition>)" returns the token.

Arda-SystemsOAM — read by the CI drift workflow only

Section titled “Arda-SystemsOAM — read by the CI drift workflow only”

Read by runtime-platform-drift.yml (the parallel workflow Phase 4 introduces) via OP_SERVICE_ACCOUNT_TOKEN. The GHA secret’s 1P scope is Arda-SystemsOAM (set in Phase 1; no change in Phase 4 per pre-design follow-up B5 / G-16 option (a) — the drift workflow does not require per-partition vault access). The workflow needs the Postmark account-level tokens to authenticate Postmark Account API probes for each partition’s Sender Signature.

VaultItemFieldConsumer
Arda-SystemsOAMPostmark-Prodcredentialruntime-platform-drift.yml for Postmark Account API probes against PostmarkProd (prod + demo Sender Signatures)
Arda-SystemsOAMPostmark-NonProdcredentialruntime-platform-drift.yml for Postmark Account API probes against PostmarkNonProd (dev + stage Sender Signatures)

Phase 4 does not introduce these items — they exist from Phase 1. The drift workflow inherits the same authentication pattern corporate-drift already uses. Per-partition SM-secret state is verified via AWS SDK (describe-secret) with the workflow’s existing AWS OIDC role; no additional 1P scope expansion is required.

Phase 3’s Free-Kanban-Generator-Postmark-Server item lives in Arda-CorporateOAM (DQ-R1-007). Phase 4 does not read it. Listed here only to forestall confusion — the Corporate vault is exclusively a Phase 3 / future-Corporate-consumer concern.

9. External resources Phase 4 references but does NOT create

Section titled “9. External resources Phase 4 references but does NOT create”
External resourceSourceHow Phase 4 uses it
ardamails.com root zonePhase 2 (RootDnsStack); CFN export arda-ardamails-zonePhase 4’s WriteNSRecordsToUpstreamDns writes NS-delegation records into this zone per partition (one record per partition).
AllowCreatingNSRecordsRole (Root account)Phase 2; CFN export arda-allow-create-ns-record-rolePhase 4’s NS-delegation Custom Resource Lambda assumes this role for the cross-account write into ardamails.com. Unchanged from Phase 3 ‘s same usage.
WriteNSRecordsToUpstreamDns constructPhase 2 (constructs/xgress/write-ns-records-to-upstream-dns.ts)Phase 4 instantiates per partition.
DnsZone, DnsEmailRecords xgress constructsPhase 3 (constructs/xgress/)Phase 4 instantiates per partition.
PostmarkSendingDomain thin-wrapperPhase 3 (platform/constructs/postmark/sending-domain.ts)Phase 4’s tools/register-partition-mail-signature.ts uses the thin-wrapper to register the partition’s Sender Signature. PostmarkServer thin-wrapper is not used (per-tenant servers are Phase 5b).
Per-partition pod IRSA roleExisting infrastructure stack; export ${publishingPrefix}-EksPodRoleArn (eks-stack.ts:250)Phase 4’s two IAM roles (DNS-records role, fallback role) reference this role’s name pattern via their trust policy ArnLike condition. The export is not imported as an ARN.
corporate-drift workflow + driverPhase 3Phase 4 extracts shared utilities into tools/lib/drift/ (DQ-R1-018); corporate-drift continues to function unchanged.
Existing partitionSecrets.cfn.yaml + amm.sh NoEcho-parameter patternPre-Phase-4 (predates this project)Phase 4’s δ.1 Postmark account-token delivery mirrors this pattern via CDK SecretValue.cfnParameter().

10. Surfaces Phase 4 does NOT add or remove

Section titled “10. Surfaces Phase 4 does NOT add or remove”
SurfacePhase 4 stance
PostmarkServer thin-wrapperUsed by Phase 3 (Free Kanban Tool server); not used by Phase 4 (per-tenant servers are Phase 5b). The construct remains available for Phase 5b.
tools/corporate-cli.ts operator-facing entry-pointContinues to exist and function. Phase 4 extracts shared helpers into tools/lib/ (B3 minimal cut); corporate-cli’s Phase-3 Corporate flow is unaffected.
corporate-drift.yml workflowNot renamed per DQ-R1-018; continues to run on its existing schedule. Phase 4 extracts shared utilities (DQ-R1-018); the workflow consumes the extracted helpers.
kyle.ardamails.com sub-zoneNot provisioned per DQ-R1-021 (partition suspended). The name remains reserved at the ardamails.com level (REQ-PART-006 / REQ-IAC-007) so it cannot be appropriated as a tenant slug.
Root account’s AllowCreatingNSRecordsRole instantiationUnchanged at the CloudFormation level post-Phase-4 (REQ-IAC-002 enforces this byte-identically). Phase 4 generalizes the construct but the existing call-site continues to produce identical synth output.
Apex SPF / DMARC on ardamails.comOut of project; not added by Phase 4.
AllowCreatingNSRecordsRole.allowedParentHostedZoneIds scope-tightening (Root use case)Out of project; not tightened by Phase 4. Future security-hardening project owns this.
ConsumerReads whatUsed for
Phase 5b operations Helm chartAll six per-partition -API- CFN exports (§ 1)ESO ExternalSecret definitions; STS-AssumeRole credential providers for the two IAM roles; tenant DNS write paths
Phase 5b EmailConfigurationService (L3)Encryption-key SM secret value (via ESO-projected K8s Secret); EmailEncryptionKeyFallbackRoleArn (via Helm values)Initializes TokenCipher at startup; assumes the fallback role for SDK cache-miss path
Phase 5b runtime DNS writesEmailDnsProvisioningRoleArn (via Helm values; conditional on DQ-R1-023’s resolution)Per-tenant DKIM TXT + Return-Path CNAME record writes into the partition’s mail sub-zone (if per-tenant Signatures introduced)
runtime-platform-drift workflowThe CFN exports + Postmark Account API + DNSPer-partition cross-seam state assertion
corporate-drift workflowThe shared utilities (tools/lib/drift/)Existing Corporate Sender Signature drift assertion; unchanged behaviour post-extraction

Copyright: (c) Arda Systems 2025-2026, All rights reserved