From 4e84069aa6aefedebb3ee7de6a64dfe9c5d8fef8 Mon Sep 17 00:00:00 2001 From: Dave Arnold Date: Thu, 4 Jun 2026 13:17:49 -0400 Subject: [PATCH] chore: end-of-session commit (3 files changed) --- deploy/stacksets.tf | 61 +++++++++++++++++++ deploy/variables.tf | 12 ++++ ...stackset-sc-automation-codebuild-role.yaml | 61 +++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 deploy/stacksets.tf create mode 100644 service-catalog/stackset-sc-automation-codebuild-role.yaml diff --git a/deploy/stacksets.tf b/deploy/stacksets.tf new file mode 100644 index 0000000..6ecd35a --- /dev/null +++ b/deploy/stacksets.tf @@ -0,0 +1,61 @@ +# --------------------------------------------------------------------------- +# CloudFormation StackSet: sc-automation-codebuild-role +# +# Deploys an IAM cross-account role to every account in the target OU so the +# tf-run-executor CodeBuild project in csvd-dev can assume it to run Terraform +# in each target account. +# +# PREREQUISITE: SERVICE_MANAGED StackSets can only be managed from the AWS +# Organizations management account OR a delegated CloudFormation StackSets +# administrator account. If csvd-dev (229685449397) is not one of those, apply +# this module with credentials for the management/delegated-admin account by +# either: +# - setting AWS_PROFILE to a management-account profile, or +# - adding `assume_role { role_arn = "..." }` to the provider in provider.tf. +# +# Auto-deployment is enabled: accounts joining the OU automatically receive the +# role. Accounts removed from the OU lose the role (retain = false). +# --------------------------------------------------------------------------- + +resource "aws_cloudformation_stack_set" "sc_automation_role" { + name = "sc-automation-codebuild-role" + description = "Deploys sc-automation-codebuild-role IAM role to all accounts in the target OU" + + permission_model = "SERVICE_MANAGED" + + auto_deployment { + enabled = true + retain_stacks_on_account_removal = false + } + + capabilities = ["CAPABILITY_NAMED_IAM"] + + # Template is rendered inline from the file so no S3 dependency is required. + template_body = file("${path.module}/../service-catalog/stackset-sc-automation-codebuild-role.yaml") + + parameters = { + CodeBuildAccountId = var.codebuild_account_id + } + + tags = { + Project = "sc-automation" + ManagedBy = "terraform" + } +} + +resource "aws_cloudformation_stack_set_instance" "sc_automation_role" { + stack_set_name = aws_cloudformation_stack_set.sc_automation_role.name + region = data.aws_region.current.name + + # Target the entire OU; CloudFormation resolves account membership dynamically. + deployment_targets { + organizational_unit_ids = [var.stackset_target_ou_id] + } + + # Allow up to 5 concurrent stack instance deployments; tolerate no failures + # so a bad account never silently goes un-deployed. + operation_preferences { + failure_tolerance_count = 0 + max_concurrent_count = 5 + } +} diff --git a/deploy/variables.tf b/deploy/variables.tf index 4558239..e93c9ce 100644 --- a/deploy/variables.tf +++ b/deploy/variables.tf @@ -80,3 +80,15 @@ variable "principal_arns" { type = list(string) default = [] } + +variable "stackset_target_ou_id" { + description = "AWS Organizations OU ID to target with the sc-automation-codebuild-role StackSet (e.g. \"ou-xxxx-xxxxxxxx\")" + type = string + # e.g. "ou-xxxx-xxxxxxxx" +} + +variable "codebuild_account_id" { + description = "AWS account ID of the csvd-dev account where tf-run-executor-codebuild runs; used as the trust principal in the cross-account role" + type = string + default = "229685449397" +} diff --git a/service-catalog/stackset-sc-automation-codebuild-role.yaml b/service-catalog/stackset-sc-automation-codebuild-role.yaml new file mode 100644 index 0000000..ab7d3b7 --- /dev/null +++ b/service-catalog/stackset-sc-automation-codebuild-role.yaml @@ -0,0 +1,61 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: > + Deploys sc-automation-codebuild-role in each target account via a SERVICE_MANAGED + CloudFormation StackSet. Every account in the target OU receives the role + automatically. New accounts joining the OU get the role on vending (auto_deployment + enabled). See ADR-004 in sc-lambda-ghactions for the full design rationale. + +Parameters: + CodeBuildAccountId: + Type: String + Default: "229685449397" + Description: > + AWS account ID of the csvd-dev account where the tf-run-executor CodeBuild + project runs. The IAM role tf-run-executor-codebuild in this account is + granted sts:AssumeRole on this target-account role. + AllowedPattern: "[0-9]{12}" + ConstraintDescription: Must be a 12-digit AWS account ID. + +Resources: + SCAutomationCodeBuildRole: + Type: AWS::IAM::Role + Properties: + RoleName: sc-automation-codebuild-role + Description: > + Cross-account role assumed by the tf-run-executor CodeBuild service role in + csvd-dev to run Terraform in this account. Deployed and managed via + CloudFormation StackSet (sc-lambda-ghactions). + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowSCAutomationCodeBuild + Effect: Allow + Principal: + AWS: !Sub "arn:${AWS::Partition}:iam::${CodeBuildAccountId}:role/tf-run-executor-codebuild" + Action: sts:AssumeRole + Condition: + StringEquals: + # ExternalId = the target account's own ID, preventing confused-deputy + # attacks across accounts in the same org. The executor build passes + # the target account ID as ExternalId at assume-role time. + sts:ExternalId: !Ref AWS::AccountId + ManagedPolicyArns: + # Initial baseline: AdministratorAccess. + # Future hardening: replace with a least-privilege customer-managed policy + # once the full set of IAM actions required by each product workspace is + # known. Track in a follow-up ADR. + - !Sub "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + Tags: + - Key: Project + Value: sc-automation + - Key: ManagedBy + Value: cloudformation-stackset + - Key: CreatedBy + Value: sc-lambda-ghactions + +Outputs: + RoleArn: + Description: ARN of the sc-automation-codebuild-role IAM role + Value: !GetAtt SCAutomationCodeBuildRole.Arn + Export: + Name: sc-automation-codebuild-role-arn