From ef1f94dfc62f7b14c2c73ec54018bac63b6c6a17 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 24 Oct 2024 17:39:09 -0400 Subject: [PATCH] massively overhaul the CI/CD This should make managing the stack in the management account easier --- .github/workflows/main.yaml | 35 ++-- stackset-build-template.yaml | 78 +++++++ stackset-deploy-template.yaml | 49 +++++ stacksets-build-template.yaml | 31 --- stacksets-deploy-template.yaml | 32 --- stacksets/gha-build/stackset.yaml | 316 +++++++++++++++++++++++------ stacksets/gha-build/template.yaml | 257 ----------------------- stacksets/gha-deploy/stackset.yaml | 207 +++++++++++++++---- stacksets/gha-deploy/template.yaml | 177 ---------------- template.yaml | 30 --- 10 files changed, 566 insertions(+), 646 deletions(-) create mode 100644 stackset-build-template.yaml create mode 100644 stackset-deploy-template.yaml delete mode 100644 stacksets-build-template.yaml delete mode 100644 stacksets-deploy-template.yaml delete mode 100644 stacksets/gha-build/template.yaml delete mode 100644 stacksets/gha-deploy/template.yaml delete mode 100644 template.yaml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index fa125eb..6f096fa 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -48,13 +48,24 @@ jobs: - name: Install AWS SAM uses: aws-actions/setup-sam@v2 - # FIXME: We're only validating the top-level template and not the rest. - - name: Validate artifact - run: sam validate --lint + - name: Validate artifact (deploy) + run: sam validate --lint -t stackset-deploy-template.yaml + + - name: Validate artifact (build) + run: sam validate --lint -t stackset-build-template.yaml + + - name: Validate artifact (SAM artifact) + run: sam validate --lint -t stacksets/gha-build/sam-deployment.yaml + + - name: Validate artifact (build stackset) + run: sam validate --lint -t stacksets/gha-build/stackset.yaml + + - name: Validate artifact (deploy stackset) + run: sam validate --lint -t stacksets/gha-deploy/stackset.yaml - name: Synethsize StackSet templates run: | - for _f in $(find . -type f -name 'stackset.yaml'); do + for _f in $(find . -type f -name 'stackset-*-template.yaml'); do _dir="$(dirname $_f)/" \ yq \ -i \ @@ -67,7 +78,7 @@ jobs: shell: bash run: | sam package \ - --template template.yaml \ + --template stacksets/gha-deploy/stackset.yaml \ --s3-bucket aws-sam-cli-sourcebucket-225989329251-us-east-1 \ --s3-prefix ${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG_URL }}/${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}/${{ env.GITHUB_REF_SLUG_URL }} \ --region us-east-1 \ @@ -78,22 +89,22 @@ jobs: shell: bash run: | sam package \ - --template stacksets-build-template.yaml \ + --template stackset-build-template.yaml \ --s3-bucket aws-sam-cli-sourcebucket-225989329251-us-east-1 \ --s3-prefix ${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG_URL }}/${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}/${{ env.GITHUB_REF_SLUG_URL }} \ --region us-east-1 \ - --output-template-file packaged-stacksets-build-template.yaml + --output-template-file packaged-stackset-build-template.yaml - name: Upload SAM artifact (Deploy Account) id: upload-sam-stackset-deploy-template shell: bash run: | sam package \ - --template stacksets-deploy-template.yaml \ + --template stackset-deploy-template.yaml \ --s3-bucket aws-sam-cli-sourcebucket-225989329251-us-east-1 \ --s3-prefix ${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG_URL }}/${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}/${{ env.GITHUB_REF_SLUG_URL }} \ --region us-east-1 \ - --output-template-file packaged-stacksets-deploy-template.yaml + --output-template-file packaged-stackset-deploy-template.yaml - name: Store Artifacts uses: ServerlessOpsIO/gha-store-artifacts@v1 @@ -147,8 +158,8 @@ jobs: uses: ServerlessOpsIO/gha-deploy-aws-sam@v1 with: aws_account_id: ${{ secrets.AWS_MANAGEMENT_ACCOUNT_ID }} - template_file: packaged-stacksets-build-template.yaml - stack_name: "${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}-${{ env.GITHUB_EVENT_REF_SLUG_URL }}-build" + template_file: packaged-stackset-build-template.yaml + stack_name: "${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}-${{ env.GITHUB_EVENT_REF_SLUG_URL }}-stackset-build" cfn_capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND env_json: ${{ toJson(env) }} secrets_json: ${{ toJson(secrets) }} @@ -204,7 +215,7 @@ jobs: uses: ServerlessOpsIO/gha-deploy-aws-sam@v1 with: aws_account_id: ${{ secrets.AWS_MANAGEMENT_ACCOUNT_ID }} - stack_name: "${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}-${{ env.GITHUB_EVENT_REF_SLUG_URL }}-deploy" + stack_name: "${{ env.GITHUB_REPOSITORY_NAME_PART_SLUG_URL }}-${{ env.GITHUB_EVENT_REF_SLUG_URL }}-stackset-deploy" template_file: packaged-stacksets-deploy-template.yaml cfn_capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND env_json: ${{ toJson(env) }} diff --git a/stackset-build-template.yaml b/stackset-build-template.yaml new file mode 100644 index 0000000..083dca0 --- /dev/null +++ b/stackset-build-template.yaml @@ -0,0 +1,78 @@ +Metadata: + GhaStack: + localTemplateFile: &gha_stackset_body ./stacksets/gha-build/stackset.yaml + SamStack: + localTemplateFile: &sam_template_body ./stacksets/gha-build/sam-deployment.yaml + +AWSTemplateFormatVersion: '2010-09-09' +Transform: + - 'AWS::Serverless-2016-10-31' +Description: GitHib Actions integration stacks + +Parameters: + TargetOuIds: + Type: CommaDelimitedList + Description: Comma separated list of OUs + TargetRegions: + Type: CommaDelimitedList + Description: Comma separated list of regions + AwsOrganizationId: + Type: String + Description: AWS Organization ID + +Resources: + OrgCiCdSamArtifacts: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: CiCdSamArtifacts + Description: AWS SAM Deployment + Parameters: + - ParameterKey: AwsOrganizationId + ParameterValue: !Ref AwsOrganizationId + - ParameterKey: BuildAccount + ParameterValue: 'true' + StackInstancesGroup: + - DeploymentTargets: + OrganizationalUnitIds: !Ref TargetOuIds + Regions: !Ref TargetRegions + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: false + ManagedExecution: + Active: true + OperationPreferences: + RegionConcurrencyType: PARALLEL + FailureToleranceCount: 1 + MaxConcurrentCount: 5 + PermissionModel: SERVICE_MANAGED + TemplateBody: *sam_template_body + + + OrgCiCdGhaBuild: + Type: AWS::CloudFormation::StackSet + DependsOn: OrgCiCdSamArtifacts + Properties: + StackSetName: CiCdGhaBuild + Description: GHA CI/CD Deployment Build + Parameters: + - ParameterKey: DeployBucketArn + ParameterValue: '/org/cicd/SamDeployBucketArn' + - ParameterKey: AwsOrganizationId + ParameterValue: !Ref AwsOrganizationId + StackInstancesGroup: + - DeploymentTargets: + OrganizationalUnitIds: !Ref TargetOuIds + Regions: !Ref TargetRegions + Capabilities: + - CAPABILITY_NAMED_IAM + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: false + ManagedExecution: + Active: true + OperationPreferences: + RegionConcurrencyType: PARALLEL + FailureToleranceCount: 1 + MaxConcurrentCount: 5 + PermissionModel: SERVICE_MANAGED + TemplateBody: *gha_stackset_body \ No newline at end of file diff --git a/stackset-deploy-template.yaml b/stackset-deploy-template.yaml new file mode 100644 index 0000000..b76421f --- /dev/null +++ b/stackset-deploy-template.yaml @@ -0,0 +1,49 @@ +Metadata: + localTemplateFile: &template_body stacksets/gha-deploy/template.yaml + +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: AWS account infrastructure stackset (GHA Deployments) + +Parameters: + TargetOuIds: + Type: CommaDelimitedList + Description: List of OUs + TargetRegions: + Type: CommaDelimitedList + Description: Regions to deploy to + CicdAwsAccountId: + Type: String + Description: AWS Account ID for CI/CD + DeployBucketArn: + Type: String + Description: S3 bucket ARN for deployment + +Resources: + OrgCiCdGhaDeploy: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: CiCdGhaDeploy + Description: GHA CI/CD Deployment + Parameters: + - ParameterKey: CicdAwsAccountId + ParameterValue: !Ref CicdAwsAccountId + - ParameterKey: DeployBucketArn + ParameterValue: !Ref DeployBucketArn + Capabilities: + - CAPABILITY_NAMED_IAM + StackInstancesGroup: + - DeploymentTargets: + OrganizationalUnitIds: !Ref TargetOuIds + Regions: !Ref TargetRegions + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: false + ManagedExecution: + Active: true + OperationPreferences: + RegionConcurrencyType: PARALLEL + FailureToleranceCount: 1 + MaxConcurrentCount: 5 + PermissionModel: SERVICE_MANAGED + TemplateBody: *template_body \ No newline at end of file diff --git a/stacksets-build-template.yaml b/stacksets-build-template.yaml deleted file mode 100644 index c592781..0000000 --- a/stacksets-build-template.yaml +++ /dev/null @@ -1,31 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: - - 'AWS::Serverless-2016-10-31' -Description: GitHib Actions integration stacks - -Parameters: - TargetOuIds: - Type: String - Description: Comma separated listist of OUs - TargetRegions: - Type: String - Description: Comma separated list of regions - AwsOrganizationId: - Type: String - Description: AWS Organization ID - CicdAwsAccountId: - Type: String - Description: AWS Account ID for CI/CD - CiCdOuIds: - Type: String - Description: Comma separated listist of OUs - -Resources: - GhaBuildStackSet: - Type: AWS::Serverless::Application - Properties: - Location: './stacksets/gha-build/stackset.yaml' - Parameters: - TargetOuIds: !Ref CiCdOuIds - TargetRegions: !Ref TargetRegions - AwsOrganizationId: !Ref AwsOrganizationId diff --git a/stacksets-deploy-template.yaml b/stacksets-deploy-template.yaml deleted file mode 100644 index 55038dc..0000000 --- a/stacksets-deploy-template.yaml +++ /dev/null @@ -1,32 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: - - 'AWS::Serverless-2016-10-31' -Description: GitHib Actions integration stacks - -Parameters: - TargetOuIds: - Type: String - Description: Comma separated listist of OUs - TargetRegions: - Type: String - Description: Comma separated list of regions - AwsOrganizationId: - Type: String - Description: AWS Organization ID - CicdAwsAccountId: - Type: String - Description: AWS Account ID for CI/CD - CiCdOuIds: - Type: String - Description: Comma separated listist of OUs - -Resources: - GhaDeployStackSet: - Type: AWS::Serverless::Application - Properties: - Location: './stacksets/gha-deploy/stackset.yaml' - Parameters: - TargetOuIds: !Ref TargetOuIds - TargetRegions: !Ref TargetRegions - CicdAwsAccountId: !Ref CicdAwsAccountId - DeployBucketArn: !Sub 'arn:aws:s3:::aws-sam-cli-sourcebucket-${CicdAwsAccountId}-us-east-1' diff --git a/stacksets/gha-build/stackset.yaml b/stacksets/gha-build/stackset.yaml index 438c485..3fe30e7 100644 --- a/stacksets/gha-build/stackset.yaml +++ b/stacksets/gha-build/stackset.yaml @@ -1,77 +1,259 @@ - -Metadata: - GhaStack: - localTemplateFile: &gha_template_body ./template.yaml - SamStack: - localTemplateFile: &sam_template_body ./sam-deployment.yaml - AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: AWS account infrastructure stackset (GHA Build) +Description: GitHub Actions Build Account Parameters: - TargetOuIds: - Type: CommaDelimitedList - Description: List of OUs - TargetRegions: - Type: CommaDelimitedList - Description: Regions to deploy to + IdpName: + Type: String + Description: "Name of IAM Identity Provider" + Default: "token.actions.githubusercontent.com" + + DeployBucketArn: + Type: AWS::SSM::Parameter::Value + Description: "ARN of deployment bucket" + AwsOrganizationId: Type: String - Description: AWS Organization ID + Description: "AWS Org ID of accounts allowed to access S3 Bucket" Resources: - OrgCiCdSamArtifacts: - Type: AWS::CloudFormation::StackSet + ### + # IAM Roles + ### + GitHubActionsBuildRole: + Type: AWS::IAM::Role + Properties: + RoleName: "GitHubActionsBuildRole" + Description: "GitHubActions Build Role" + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Federated: !Ref GitHubActionsOidcProvider + Condition: + ForAllValues:StringLike: + "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" + "token.actions.githubusercontent.com:sub": [ + "repo:ServerlessOpsIO/*:ref:refs/heads/*", + "repo:ServerlessOpsIO/*:ref:refs/tags/*", + "repo:ServerlessOpsIO/*:environment:*", + ] + Action: + - 'sts:AssumeRoleWithWebIdentity' + Policies: + # Needed for SAM validate + - PolicyName: Iam + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: 'iam:ListPolicies' + Resource: '*' + - PolicyName: SsmParams + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: 'ssm:GetParameter' + Resource: !Sub "arn:aws:ssm:${AWS::Region}:*:parameter/org/cicd/*" + - PolicyName: SharedS3DeployBucket + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:List*' + - 's3:GetBucket*' + Resource: + - !Ref DeployBucketArn + - PolicyName: SharedS3DeployBucketObjects + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:DeleteObject' + - 's3:GetObject*' + - 's3:List*' + - 's3:PutObject*' + Resource: + # We group artifacts by GitHub org in case we need to accommodate more orgs. + - !Sub "${DeployBucketArn}/serverlessopsio/*" + # SAM templates are written at the root. + - !Sub "${DeployBucketArn}/*.template" + - PolicyName: SharedS3DeployBucketObjectsDenyMainDelete + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Deny + Action: + - 's3:DeleteObject' + Resource: + - !Sub "${DeployBucketArn}/serverlessopsio/*/main/*" + - !Sub "${DeployBucketArn}/*.template" + - PolicyName: SarS3DeployBucket + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:List*' + - 's3:GetBucket*' + Resource: + - !GetAtt SarPublishingBucket.Arn + - PolicyName: SarS3DeployBucketObjects + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:DeleteObject' + - 's3:GetObject*' + - 's3:List*' + - 's3:PutObject*' + Resource: + # We group artifacts by GitHub org in case we need to accommodate more orgs. + - !Sub "${SarPublishingBucket.Arn}/serverlessopsio/*" + # SAM templates are written at the root. + - !Sub "${SarPublishingBucket.Arn}/*.template" + - PolicyName: SarS3DeployBucketObjectsDenyMainDelete + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Deny + Action: + - 's3:DeleteObject' + Resource: + - !Sub "${SarPublishingBucket.Arn}/serverlessopsio/*/main/*" + - !Sub "${SarPublishingBucket.Arn}/*.template" + - PolicyName: SarApplications + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'serverlessrepo:CreateApplication' + - 'serverlessrepo:GetApplication' + - 'serverlessrepo:ListApplications' + - 'serverlessrepo:PublishApplication' + - 'serverlessrepo:UpdateApplication' + - 'serverlessrepo:DeleteApplication' + - 'serverlessrepo:PutApplicationPolicy' + - 'serverlessrepo:CreateApplicationVersion' + - 'serverlessrepo:CreateCloudFormationTemplate' + Resource: '*' + - PolicyName: STS + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'sts:AssumeRole' + - 'sts:TagSession' + Resource: + - 'arn:aws:iam::*:role/GitHubActionsCfnDeployRole' + - 'arn:aws:iam::*:role/GitHubActionsTerraformDeployRole' + - PolicyName: EcrLogin + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'ecr:GetAuthorizationToken' + Resource: '*' + - PolicyName: EcrPull + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'ecr:BatchGetImage' + - 'ecr:GetDownloadUrlForLayer' + Resource: + - !Sub "arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/*" + - PolicyName: EcrPublish + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'ecr:BatchCheckLayerAvailability' + - 'ecr:CompleteLayerUpload' + - 'ecr:InitiateLayerUpload' + - 'ecr:PutImage' + - 'ecr:UploadLayerPart' + - 'ecr:DescribeRepositories' + - 'ecr:CreateRepository' + - 'ecr:SetRepositoryPolicy' + Resource: + - !Sub "arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/serverlessopsio/*" + + GitHubActionsOidcProvider: + Type: AWS::IAM::OIDCProvider + Properties: + ClientIdList: + - sts.amazonaws.com + ThumbprintList: + - 6938fd4d98bab03faadb97b34396831e3780aea1 + - 1c58a3a8518e8759bf075b76b750d4f2df264fcd + Url: !Sub "https://${IdpName}" + + + SarPublishingBucket: + Type: AWS::S3::Bucket + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + BucketName: !Sub 'aws-sar-${AWS::AccountId}-${AWS::Region}' + # Have Bucket policy handle these things. Otherwise we can end up with conflicts that + # break configuration. + PublicAccessBlockConfiguration: + BlockPublicPolicy: true + BlockPublicAcls: true + IgnorePublicAcls: true + RestrictPublicBuckets: true + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: aws:kms + VersioningConfiguration: + Status: Enabled + + SarPublishingBucketPolicy: + Type: AWS::S3::BucketPolicy Properties: - StackSetName: CiCdSamArtifacts - Description: AWS SAM Deployment - Parameters: - - ParameterKey: AwsOrganizationId - ParameterValue: !Ref AwsOrganizationId - - ParameterKey: BuildAccount - ParameterValue: 'true' - StackInstancesGroup: - - DeploymentTargets: - OrganizationalUnitIds: !Ref TargetOuIds - Regions: !Ref TargetRegions - AutoDeployment: - Enabled: true - RetainStacksOnAccountRemoval: false - ManagedExecution: - Active: true - OperationPreferences: - RegionConcurrencyType: PARALLEL - FailureToleranceCount: 1 - MaxConcurrentCount: 5 - PermissionModel: SERVICE_MANAGED - TemplateBody: *sam_template_body + Bucket: !Ref SarPublishingBucket + PolicyDocument: + Statement: + - Action: + - s3:GetObject + Effect: Allow + Resource: + - !Sub "${SarPublishingBucket.Arn}/*" + Principal: + Service: serverlessrepo.amazonaws.com + Condition: + StringEquals: + "aws:SourceOrgID": + - !Ref AwsOrganizationId - OrgCiCdGhaBuild: - Type: AWS::CloudFormation::StackSet - DependsOn: OrgCiCdSamArtifacts + ### + #SSM Parameters + ### + GitHubActionsIamRoleArnSsmParam: + Type: AWS::SSM::Parameter Properties: - StackSetName: CiCdGhaBuild - Description: GHA CI/CD Deployment Build - Parameters: - - ParameterKey: DeployBucketArn - ParameterValue: '/org/cicd/SamDeployBucketArn' - - ParameterKey: AwsOrganizationId - ParameterValue: !Ref AwsOrganizationId - StackInstancesGroup: - - DeploymentTargets: - OrganizationalUnitIds: !Ref TargetOuIds - Regions: !Ref TargetRegions - Capabilities: - - CAPABILITY_NAMED_IAM - AutoDeployment: - Enabled: true - RetainStacksOnAccountRemoval: false - ManagedExecution: - Active: true - OperationPreferences: - RegionConcurrencyType: PARALLEL - FailureToleranceCount: 1 - MaxConcurrentCount: 5 - PermissionModel: SERVICE_MANAGED - TemplateBody: *gha_template_body + Name: "/org/cicd/GitHubActionsBuildRoleArn" + Type: "String" + Description: "GitHubActions IAM Role ARN" + Value: !GetAtt GitHubActionsBuildRole.Arn + + SarPublishingBucketArnSsmParam: + Type: AWS::SSM::Parameter + Properties: + Name: "/org/cicd/SarPublishingBucketArn" + Type: "String" + Description: "SAR Publishing Bucket ARN" + Value: !GetAtt SarPublishingBucket.Arn + + diff --git a/stacksets/gha-build/template.yaml b/stacksets/gha-build/template.yaml deleted file mode 100644 index 5c16146..0000000 --- a/stacksets/gha-build/template.yaml +++ /dev/null @@ -1,257 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: GitHub Actions Build Account - -Parameters: - IdpName: - Type: String - Description: "Name of IAM Identity Provider" - Default: "token.actions.githubusercontent.com" - - DeployBucketArn: - Type: AWS::SSM::Parameter::Value - Description: "ARN of deployment bucket" - - AwsOrganizationId: - Type: String - Description: "AWS Org ID of accounts allowed to access S3 Bucket" - -Resources: - ### - # IAM Roles - ### - GitHubActionsBuildRole: - Type: AWS::IAM::Role - Properties: - RoleName: "GitHubActionsBuildRole" - Description: "GitHubActions Build Role" - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Federated: !Ref GitHubActionsOidcProvider - Condition: - ForAllValues:StringLike: - "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" - "token.actions.githubusercontent.com:sub": [ - "repo:ServerlessOpsIO/*:ref:refs/heads/*", - "repo:ServerlessOpsIO/*:ref:refs/tags/*", - "repo:ServerlessOpsIO/*:environment:*", - ] - Action: - - 'sts:AssumeRoleWithWebIdentity' - Policies: - # Needed for SAM validate - - PolicyName: Iam - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: 'iam:ListPolicies' - Resource: '*' - - PolicyName: SsmParams - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: 'ssm:GetParameter' - Resource: !Sub "arn:aws:ssm:${AWS::Region}:*:parameter/org/cicd/*" - - PolicyName: SharedS3DeployBucket - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:List*' - - 's3:GetBucket*' - Resource: - - !Ref DeployBucketArn - - PolicyName: SharedS3DeployBucketObjects - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:DeleteObject' - - 's3:GetObject*' - - 's3:List*' - - 's3:PutObject*' - Resource: - # We group artifacts by GitHub org in case we need to accommodate more orgs. - - !Sub "${DeployBucketArn}/serverlessopsio/*" - # SAM templates are written at the root. - - !Sub "${DeployBucketArn}/*.template" - - PolicyName: SharedS3DeployBucketObjectsDenyMainDelete - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Deny - Action: - - 's3:DeleteObject' - Resource: - - !Sub "${DeployBucketArn}/serverlessopsio/*/main/*" - - !Sub "${DeployBucketArn}/*.template" - - PolicyName: SarS3DeployBucket - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:List*' - - 's3:GetBucket*' - Resource: - - !GetAtt SarPublishingBucket.Arn - - PolicyName: SarS3DeployBucketObjects - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:DeleteObject' - - 's3:GetObject*' - - 's3:List*' - - 's3:PutObject*' - Resource: - # We group artifacts by GitHub org in case we need to accommodate more orgs. - - !Sub "${SarPublishingBucket.Arn}/serverlessopsio/*" - # SAM templates are written at the root. - - !Sub "${SarPublishingBucket.Arn}/*.template" - - PolicyName: SarS3DeployBucketObjectsDenyMainDelete - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Deny - Action: - - 's3:DeleteObject' - Resource: - - !Sub "${SarPublishingBucket.Arn}/serverlessopsio/*/main/*" - - !Sub "${SarPublishingBucket.Arn}/*.template" - - PolicyName: SarApplications - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'serverlessrepo:CreateApplication' - - 'serverlessrepo:GetApplication' - - 'serverlessrepo:ListApplications' - - 'serverlessrepo:PublishApplication' - - 'serverlessrepo:UpdateApplication' - - 'serverlessrepo:DeleteApplication' - - 'serverlessrepo:PutApplicationPolicy' - - 'serverlessrepo:CreateApplicationVersion' - - 'serverlessrepo:CreateCloudFormationTemplate' - Resource: '*' - - PolicyName: STS - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'sts:AssumeRole' - - 'sts:TagSession' - Resource: - - 'arn:aws:iam::*:role/GitHubActionsCfnDeployRole' - - 'arn:aws:iam::*:role/GitHubActionsTerraformDeployRole' - - PolicyName: EcrLogin - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'ecr:GetAuthorizationToken' - Resource: '*' - - PolicyName: EcrPull - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'ecr:BatchGetImage' - - 'ecr:GetDownloadUrlForLayer' - Resource: - - !Sub "arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/*" - - PolicyName: EcrPublish - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'ecr:BatchCheckLayerAvailability' - - 'ecr:CompleteLayerUpload' - - 'ecr:InitiateLayerUpload' - - 'ecr:PutImage' - - 'ecr:UploadLayerPart' - - 'ecr:DescribeRepositories' - - 'ecr:CreateRepository' - - 'ecr:SetRepositoryPolicy' - Resource: - - !Sub "arn:${AWS::Partition}:ecr:${AWS::Region}:${AWS::AccountId}:repository/serverlessopsio/*" - - GitHubActionsOidcProvider: - Type: AWS::IAM::OIDCProvider - Properties: - ClientIdList: - - sts.amazonaws.com - ThumbprintList: - - 6938fd4d98bab03faadb97b34396831e3780aea1 - - 1c58a3a8518e8759bf075b76b750d4f2df264fcd - Url: !Sub "https://${IdpName}" - - - SarPublishingBucket: - Type: AWS::S3::Bucket - DeletionPolicy: Retain - UpdateReplacePolicy: Retain - Properties: - BucketName: !Sub 'aws-sar-${AWS::AccountId}-${AWS::Region}' - # Have Bucket policy handle these things. Otherwise we can end up with conflicts that - # break configuration. - PublicAccessBlockConfiguration: - BlockPublicPolicy: true - BlockPublicAcls: true - IgnorePublicAcls: true - RestrictPublicBuckets: true - BucketEncryption: - ServerSideEncryptionConfiguration: - - ServerSideEncryptionByDefault: - SSEAlgorithm: aws:kms - VersioningConfiguration: - Status: Enabled - - SarPublishingBucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: !Ref SarPublishingBucket - PolicyDocument: - Statement: - - Action: - - s3:GetObject - Effect: Allow - Resource: - - !Sub "${SarPublishingBucket.Arn}/*" - Principal: - Service: serverlessrepo.amazonaws.com - Condition: - StringEquals: - "aws:SourceOrgID": - - !Ref AwsOrganizationId - - ### - #SSM Parameters - ### - GitHubActionsIamRoleArnSsmParam: - Type: AWS::SSM::Parameter - Properties: - Name: "/org/cicd/GitHubActionsBuildRoleArn" - Type: "String" - Description: "GitHubActions IAM Role ARN" - Value: !GetAtt GitHubActionsBuildRole.Arn - - SarPublishingBucketArnSsmParam: - Type: AWS::SSM::Parameter - Properties: - Name: "/org/cicd/SarPublishingBucketArn" - Type: "String" - Description: "SAR Publishing Bucket ARN" - Value: !GetAtt SarPublishingBucket.Arn \ No newline at end of file diff --git a/stacksets/gha-deploy/stackset.yaml b/stacksets/gha-deploy/stackset.yaml index 5fad463..9f21261 100644 --- a/stacksets/gha-deploy/stackset.yaml +++ b/stacksets/gha-deploy/stackset.yaml @@ -1,49 +1,176 @@ -Metadata: - localTemplateFile: &template_body ./template.yaml +--- AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: AWS account infrastructure stackset (GHA Deployments) +Description: AWS account infrastructure (CI/CD - deployment) Parameters: - TargetOuIds: - Type: CommaDelimitedList - Description: List of OUs - TargetRegions: - Type: CommaDelimitedList - Description: Regions to deploy to - CicdAwsAccountId: - Type: String - Description: AWS Account ID for CI/CD DeployBucketArn: Type: String - Description: S3 bucket ARN for deployment + Description: "ARN of deployment bucket (optional)" + CicdAwsAccountId: + Type: String + Description: "ID of CI/CD account" Resources: - OrgCiCdGhaDeploy: - Type: AWS::CloudFormation::StackSet + ### + # IAM Roles + ### + GitHubActionsCfnDeployRole: + Type: AWS::IAM::Role + Properties: + RoleName: "GitHubActionsCfnDeployRole" + Description: "GitHubActions Deploy Role" + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + AWS: !Sub "arn:aws:iam::${CicdAwsAccountId}:role/GitHubActionsBuildRole" + Action: + - 'sts:AssumeRole' + - 'sts:TagSession' + Policies: + - PolicyName: PassCfnRoleToServices + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: 'iam:PassRole' + Resource: !GetAtt CfnExecIamRole.Arn + - PolicyName: CloudFormationService + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "cloudformation:CreateStack" + - "cloudformation:CreateChangeSet" + - "cloudformation:DeleteStack" + - "cloudformation:DeleteChangeSet" + - "cloudformation:DescribeChangeSet" + - "cloudformation:DescribeStackEvents" + - "cloudformation:DescribeStackResource" + - "cloudformation:DescribeStackResources" + - "cloudformation:DescribeStacks" + - "cloudformation:ExecuteChangeSet" + - "cloudformation:GetTemplateSummary" + - "cloudformation:GetTemplate" + Resource: '*' + # Needed for SAM validate + - PolicyName: Iam + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: 'iam:ListPolicies' + Resource: '*' + - PolicyName: SharedS3DeployBucket + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:List*' + - 's3:GetBucket*' + Resource: + - !Ref DeployBucketArn + - PolicyName: SharedS3DeployBucketObjects + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:DeleteObject' + - 's3:GetObject*' + - 's3:List*' + - 's3:PutObject*' + Resource: + # We group artifacts by GitHub org in case we need to accommodate more orgs. + - !Sub "${DeployBucketArn}/serverlessopsio/*" + # SAM templates are written at the root. + - !Sub "${DeployBucketArn}/*.template" + - PolicyName: SharedS3DeployBucketObjectsDenyMainDelete + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Deny + Action: + - 's3:DeleteObject' + Resource: + - !Sub "${DeployBucketArn}/serverlessopsio/*/main/*" + - !Sub "${DeployBucketArn}/*.template" + - PolicyName: WritableS3Buckets + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 's3:DeleteObject' + - 's3:GetObject*' + - 's3:List*' + - 's3:PutObject*' + Resource: '*' + Condition: + StringEquals: + "aws:ResourceAccount": !Ref AWS::AccountId + - PolicyName: S3Sse + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'kms:GenerateDataKey' + Resource: '*' + - PolicyName: EcrLogin + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'ecr:GetAuthorizationToken' + Resource: '*' + - PolicyName: EcrPull + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'ecr:BatchGetImage' + - 'ecr:GetDownloadUrlForLayer' + Resource: + - !Sub "arn:${AWS::Partition}:ecr:*:${CicdAwsAccountId}:repository/*" + + CfnExecIamRole: + Type: AWS::IAM::Role + Properties: + RoleName: "CfnExecIamRole" + Description: "GitHub Actions CloudFormation execution role" + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: cloudformation.amazonaws.com + Action: + - 'sts:AssumeRole' + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AdministratorAccess + + ### + #SSM Parameters + ### + GitHubActionsCfnDeployRoleArnSsmParam: + Type: AWS::SSM::Parameter + Properties: + Name: "/org/cicd/GitHubActionsCfnDeployRoleArn" + Type: "String" + Description: "GitHubActions IAM Role ARN" + Value: !GetAtt GitHubActionsCfnDeployRole.Arn + + CfnExecIamRoleArnSsmParam: + Type: AWS::SSM::Parameter Properties: - StackSetName: CiCdGhaDeploy - Description: GHA CI/CD Deployment - Parameters: - - ParameterKey: CicdAwsAccountId - ParameterValue: !Ref CicdAwsAccountId - - ParameterKey: DeployBucketArn - ParameterValue: !Ref DeployBucketArn - Capabilities: - - CAPABILITY_NAMED_IAM - StackInstancesGroup: - - DeploymentTargets: - OrganizationalUnitIds: !Ref TargetOuIds - Regions: !Ref TargetRegions - AutoDeployment: - Enabled: true - RetainStacksOnAccountRemoval: false - ManagedExecution: - Active: true - OperationPreferences: - RegionConcurrencyType: PARALLEL - FailureToleranceCount: 1 - MaxConcurrentCount: 5 - PermissionModel: SERVICE_MANAGED - TemplateBody: *template_body \ No newline at end of file + Name: "/org/cicd/CfnExecRoleArn" + Type: "String" + Description: "CloudFormation Execution IAM Role ARN" + Value: !GetAtt CfnExecIamRole.Arn \ No newline at end of file diff --git a/stacksets/gha-deploy/template.yaml b/stacksets/gha-deploy/template.yaml deleted file mode 100644 index 9de6d1a..0000000 --- a/stacksets/gha-deploy/template.yaml +++ /dev/null @@ -1,177 +0,0 @@ - ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: AWS account infrastructure (CI/CD - deployment) - -Parameters: - DeployBucketArn: - Type: String - Description: "ARN of deployment bucket (optional)" - - CicdAwsAccountId: - Type: String - Description: "ID of CI/CD account" - -Resources: - ### - # IAM Roles - ### - GitHubActionsCfnDeployRole: - Type: AWS::IAM::Role - Properties: - RoleName: "GitHubActionsCfnDeployRole" - Description: "GitHubActions Deploy Role" - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - AWS: !Sub "arn:aws:iam::${CicdAwsAccountId}:role/GitHubActionsBuildRole" - Action: - - 'sts:AssumeRole' - - 'sts:TagSession' - Policies: - - PolicyName: PassCfnRoleToServices - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: 'iam:PassRole' - Resource: !GetAtt CfnExecIamRole.Arn - - PolicyName: CloudFormationService - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - "cloudformation:CreateStack" - - "cloudformation:CreateChangeSet" - - "cloudformation:DeleteStack" - - "cloudformation:DeleteChangeSet" - - "cloudformation:DescribeChangeSet" - - "cloudformation:DescribeStackEvents" - - "cloudformation:DescribeStackResource" - - "cloudformation:DescribeStackResources" - - "cloudformation:DescribeStacks" - - "cloudformation:ExecuteChangeSet" - - "cloudformation:GetTemplateSummary" - - "cloudformation:GetTemplate" - Resource: '*' - # Needed for SAM validate - - PolicyName: Iam - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: 'iam:ListPolicies' - Resource: '*' - - PolicyName: SharedS3DeployBucket - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:List*' - - 's3:GetBucket*' - Resource: - - !Ref DeployBucketArn - - PolicyName: SharedS3DeployBucketObjects - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:DeleteObject' - - 's3:GetObject*' - - 's3:List*' - - 's3:PutObject*' - Resource: - # We group artifacts by GitHub org in case we need to accommodate more orgs. - - !Sub "${DeployBucketArn}/serverlessopsio/*" - # SAM templates are written at the root. - - !Sub "${DeployBucketArn}/*.template" - - PolicyName: SharedS3DeployBucketObjectsDenyMainDelete - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Deny - Action: - - 's3:DeleteObject' - Resource: - - !Sub "${DeployBucketArn}/serverlessopsio/*/main/*" - - !Sub "${DeployBucketArn}/*.template" - - PolicyName: WritableS3Buckets - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 's3:DeleteObject' - - 's3:GetObject*' - - 's3:List*' - - 's3:PutObject*' - Resource: '*' - Condition: - StringEquals: - "aws:ResourceAccount": !Ref AWS::AccountId - - PolicyName: S3Sse - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'kms:GenerateDataKey' - Resource: '*' - - PolicyName: EcrLogin - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'ecr:GetAuthorizationToken' - Resource: '*' - - PolicyName: EcrPull - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - 'ecr:BatchGetImage' - - 'ecr:GetDownloadUrlForLayer' - Resource: - - !Sub "arn:${AWS::Partition}:ecr:*:${CicdAwsAccountId}:repository/*" - - CfnExecIamRole: - Type: AWS::IAM::Role - Properties: - RoleName: "CfnExecIamRole" - Description: "GitHub Actions CloudFormation execution role" - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Principal: - Service: cloudformation.amazonaws.com - Action: - - 'sts:AssumeRole' - ManagedPolicyArns: - - arn:aws:iam::aws:policy/AdministratorAccess - - ### - #SSM Parameters - ### - GitHubActionsCfnDeployRoleArnSsmParam: - Type: AWS::SSM::Parameter - Properties: - Name: "/org/cicd/GitHubActionsCfnDeployRoleArn" - Type: "String" - Description: "GitHubActions IAM Role ARN" - Value: !GetAtt GitHubActionsCfnDeployRole.Arn - - CfnExecIamRoleArnSsmParam: - Type: AWS::SSM::Parameter - Properties: - Name: "/org/cicd/CfnExecRoleArn" - Type: "String" - Description: "CloudFormation Execution IAM Role ARN" - Value: !GetAtt CfnExecIamRole.Arn \ No newline at end of file diff --git a/template.yaml b/template.yaml deleted file mode 100644 index 67e62f6..0000000 --- a/template.yaml +++ /dev/null @@ -1,30 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: - - 'AWS::Serverless-2016-10-31' -Description: AWS GitHib Actions integration stacks - -Parameters: - TargetOuIds: - Type: String - Description: Comma separated listist of OUs - TargetRegions: - Type: String - Description: Comma separated list of regions - AwsOrganizationId: - Type: String - Description: AWS Organization ID - CicdAwsAccountId: - Type: String - Description: AWS Account ID for CI/CD - CiCdOuIds: - Type: String - Description: Comma separated listist of OUs - -Resources: - GhaDeployStackManagement: - Type: AWS::Serverless::Application - Properties: - Location: './stacksets/gha-deploy/template.yaml' - Parameters: - CicdAwsAccountId: !Ref CicdAwsAccountId - DeployBucketArn: !Sub 'arn:aws:s3:::aws-sam-cli-sourcebucket-${CicdAwsAccountId}-us-east-1'