Skip to content

feat(bootstrap): policies as typed TypeScript with version and hash #122

@scottschreckengaust

Description

@scottschreckengaust

Parent

Sub-issue 2 of #120 (RFC: Least-privilege CDK bootstrap policies as code)

Branch strategy

feat/bootstrap-policies → targets feat/bootstrap-adr

Estimated review time: ~40 min

Summary

Port the three IaCRole-ABCA policy JSON blobs from DEPLOYMENT_ROLES.md into typed TypeScript modules with semver and SHA256 hash generation. This is the heaviest review in the stack — IAM actions require careful line-by-line validation.

Deliverables

  • Create cdk/src/bootstrap/policies/infrastructure.ts — typed IAM policy document (CloudFormation, IAM, VPC, DNS Firewall)
  • Create cdk/src/bootstrap/policies/application.ts — typed IAM policy document (DynamoDB, Lambda, API Gateway, Cognito, WAFv2, EventBridge, Secrets Manager)
  • Create cdk/src/bootstrap/policies/observability.ts — typed IAM policy document (Bedrock AgentCore, Guardrails, CloudWatch, X-Ray, S3, ECR, KMS, SSM, STS)
  • Create cdk/src/bootstrap/policies/index.ts — barrel export, combines all three policies
  • Create cdk/src/bootstrap/version.tsBOOTSTRAP_VERSION semver constant, computeBootstrapHash() function (SHA256 of deterministically-sorted policy JSON)
  • Create cdk/src/bootstrap/index.ts — barrel export
  • Create cdk/test/bootstrap/policies.test.ts:
    • Each policy renders to valid IAM JSON
    • Each policy < 6,144 characters when rendered
    • All SIDs are unique across the three policies
    • Policy actions match expected service prefixes
  • Create cdk/test/bootstrap/version.test.ts:
    • Hash changes when any policy action changes
    • Hash is stable across runs (deterministic)
    • Semver matches expected format
  • Generate cdk/bootstrap/policies/infrastructure.json, application.json, observability.json — rendered human-readable JSON for audit
  • Generate cdk/bootstrap/BOOTSTRAP_VERSION and cdk/bootstrap/BOOTSTRAP_HASH — machine-readable files

Key design decisions

  • Policy types use CDK's PolicyDocument/PolicyStatement classes for type safety and CDK interop
  • ACCOUNT_ID and REGION remain as substitution placeholders — resolved at bootstrap time via CF pseudo-parameters (AWS::AccountId, AWS::Region)
  • Hash computed from JSON.stringify() of sorted, normalized policy output (keys sorted, no whitespace variance)
  • Generated JSON files are committed (not .gitignored) — they serve as audit artifacts and diff-friendly change records

Acceptance criteria

  • mise //cdk:compile passes with new files
  • All tests pass (mise //cdk:test)
  • Generated JSON exactly matches DEPLOYMENT_ROLES.md content (validates port correctness)
  • No policy exceeds 6,144 character limit

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions