From c6f30664610b1f122060be5c0cb53ee4225b7e78 Mon Sep 17 00:00:00 2001 From: Simon Kok Date: Thu, 24 Oct 2024 23:20:33 +0200 Subject: [PATCH] Fix deployment bootstrap IAM PassRole permissions Issue: #755 ## Why? When an update is performed in the bootstrap repository, it will run `sam build` to generate the bootstrap stack for the deployment account. This, however, includes new versions of some of its dependencies and therefore requires the Lambda Functions to update. While updating, it requires the `iam:PassRole` permission to pass the role to the new Lambda Function version. This was not permitted, as reported in the above issue. ## What? Updated the update deployment bootstrap role to include the required permissions to pass those roles as required. Unfortunately, some of the Lambda functions relied on the `Policies` feature of SAM. This would auto generate a name for the role, thereby making it impossible to lock down permissions to the bare minimum. Hence, those functions now rely on dedicated Roles such that we can list the ARNs properly. Half of the policies for the updated bootstrap deployment role have been relocated to an IAM Managed Policy to work around the 10k inline-policy limit. Additionally, the permission to perform the `codebuild:BatchGetProjects` on the pipeline management CodeBuild project was missing. --- .../adf-bootstrap/deployment/global.yml | 274 ++++++++++++------ .../deployment/pipeline_management.yml | 6 + 2 files changed, 186 insertions(+), 94 deletions(-) diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml index 6d6220ad1..09f9ebb65 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/global.yml @@ -1620,19 +1620,38 @@ Resources: Version: !Ref ADFVersion RepositoryArn: !GetAtt CodeCommitRepository.Arn + DetermineDefaultBranchFunctionRole: + Type: "AWS::IAM::Role" + Properties: + Path: /adf/bootstrap/ + RoleName: "adf-determine-default-branch-lambda" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "lambda.amazonaws.com" + Action: + - "sts:AssumeRole" + Policies: + - PolicyName: "adf-send-slack-notification" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "codecommit:GetRepository" + Resource: + - !GetAtt CodeCommitRepository.Arn + DetermineDefaultBranchNameHandler: Type: AWS::Serverless::Function Properties: Handler: handler.lambda_handler CodeUri: lambda_codebase/determine_default_branch Description: "ADF Lambda Function - BootstrapDetermineDefaultBranchName" - Policies: - - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - codecommit:GetRepository - Resource: !GetAtt CodeCommitRepository.Arn + Role: !GetAtt DetermineDefaultBranchFunctionRole.Arn FunctionName: ADFPipelinesDetermineDefaultBranchName Metadata: BuildMethod: python3.12 @@ -1646,26 +1665,45 @@ Resources: DirectoryName: pipelines_repository DefaultBranchName: !GetAtt DetermineDefaultBranchName.DefaultBranchName + InitialCommitFunctionRole: + Type: "AWS::IAM::Role" + Properties: + Path: /adf/bootstrap/ + RoleName: "adf-initial-commit" + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "lambda.amazonaws.com" + Action: + - "sts:AssumeRole" + Policies: + - PolicyName: "adf-send-slack-notification" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - "codecommit:GetDifferences" + - "codecommit:CreateCommit" + - "codecommit:CreatePullRequest" + - "codecommit:DeleteBranch" + - "codecommit:GetBranch" + - "codecommit:CreateBranch" + - "codecommit:CreatePullRequest" + - "codecommit:DeleteBranch" + Resource: + - !GetAtt CodeCommitRepository.Arn + InitialCommitHandler: Type: AWS::Serverless::Function Properties: Handler: handler.lambda_handler CodeUri: lambda_codebase/initial_commit Description: "ADF Lambda Function - PipelinesCreateInitialCommitFunction" - Policies: - - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - codecommit:GetDifferences - - codecommit:CreateCommit - - codecommit:CreatePullRequest - - codecommit:DeleteBranch - - codecommit:GetBranch - - codecommit:CreateBranch - - codecommit:CreatePullRequest - - codecommit:DeleteBranch - Resource: !GetAtt CodeCommitRepository.Arn + Role: !GetAtt InitialCommitFunctionRole.Arn FunctionName: PipelinesCreateInitialCommitFunction Timeout: 300 Metadata: @@ -1885,6 +1923,42 @@ Resources: - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-identify-out-of-date-pipelines:*" - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-store-pipeline-definition" - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-store-pipeline-definition:*" + - Effect: "Allow" + Action: + - "iam:PassRole" + Resource: + - !GetAtt DetermineDefaultBranchFunctionRole.Arn + - !GetAtt CheckPipelineStatusLambdaRole.Arn + - !GetAtt InitialCommitFunctionRole.Arn + - !GetAtt SendSlackNotificationLambdaRole.Arn + - !GetAtt EnableCrossAccountAccessLambdaRole.Arn + Condition: + ArnEquals: + iam:AssociatedResourceArn: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:ADFPipelinesDetermineDefaultBranchName" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:CheckPipelineStatus" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:PipelinesCreateInitialCommitFunction" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:SendSlackNotification" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:UpdateCrossAccountIAM" + - Effect: "Allow" + Action: + - "iam:PassRole" + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-create-repository" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-create-update-rule" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-deployment-map-processor" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-generate-inputs" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-identify-out-of-date-pipelines" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-store-pipeline-definition" + Condition: + ArnEquals: + iam:AssociatedResourceArn: + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-create-repository" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-create-update-rule" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-deployment-map-processor" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-generate-pipeline-inputs" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-identify-out-of-date-pipelines" + - !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:adf-pipeline-management-store-pipeline-definition" - Effect: "Allow" Action: - "lambda:DeleteLayerVersion" @@ -1978,79 +2052,91 @@ Resources: - "iam:DeleteRole" Resource: - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-terraform-role" - - Sid: "IAMFullPathOnlyTag" - Effect: "Allow" - Action: - - "iam:TagRole" - - "iam:UntagRole" - Resource: - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-deployment-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codebuild-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codecommit-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codepipeline-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-readonly-automation-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-terraform-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-codepipeline" - - Sid: "IAMFullPathAndNameOnly" - Effect: "Allow" - Action: - - "iam:DeleteRolePolicy" - - "iam:GetRole" - - "iam:GetRolePolicy" - - "iam:PutRolePolicy" - - "iam:UpdateAssumeRolePolicy" - Resource: - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-deployment-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codebuild-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codecommit-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codepipeline-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-check-pipeline-status-lambda" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-management-codepipeline" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-send-slack-notification-lambda" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-readonly-automation-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-terraform-role" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/bootstrap/adf-pipeline-check-pipeline-status-lambda" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/bootstrap/adf-pipeline-send-slack-notification-lambda" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-codepipeline" - - Sid: "IAMGetOnly" - Effect: "Allow" - Action: - - "iam:GetRole" - - "iam:GetRolePolicy" - Resource: - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-*" - - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/*" - - Effect: "Allow" - Action: - - "s3:GetObject" - Resource: - - !Sub "arn:${AWS::Partition}:s3:::${BootstrapTemplatesBucketName}/adf-bootstrap/*" - - !Sub "arn:${AWS::Partition}:s3:::${SharedModulesBucket}/adf-bootstrap/*" - - Effect: "Allow" - Action: - - "codecommit:GetRepository" - Resource: - - !GetAtt CodeCommitRepository.Arn - - Effect: "Allow" - Action: - - "codebuild:BatchGetProjects" - Resource: - - !GetAtt CodeBuildProject.Arn - - Effect: "Allow" - Action: - - "sns:GetTopicAttributes" - Resource: - - !Ref PipelineSNSTopic - - Effect: Allow - Sid: "KickOffPipelineManagement" - Action: - - "states:DescribeExecution" - - "states:StartExecution" - Resource: - - !Sub arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:stateMachine:adf-bootstrap-enable-cross-account - - !Sub arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:execution:adf-bootstrap-enable-cross-account:* + + BootstrapUpdateDeploymentPolicy: + Type: "AWS::IAM::ManagedPolicy" + Properties: + Description: "Policy to perform simple bootstrap updates" + Path: /adf/bootstrap/ + Roles: + - !Ref BootstrapUpdateDeploymentRole + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "IAMFullPathOnlyTag" + Effect: "Allow" + Action: + - "iam:TagRole" + - "iam:UntagRole" + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-deployment-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codebuild-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codecommit-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codepipeline-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-readonly-automation-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-terraform-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-codepipeline" + - Sid: "IAMFullPathAndNameOnly" + Effect: "Allow" + Action: + - "iam:DeleteRolePolicy" + - "iam:GetRole" + - "iam:GetRolePolicy" + - "iam:PutRolePolicy" + - "iam:UpdateAssumeRolePolicy" + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-deployment-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-cloudformation-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codebuild-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codecommit-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-codepipeline-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-check-pipeline-status-lambda" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-management-codepipeline" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-pipeline-send-slack-notification-lambda" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-readonly-automation-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-terraform-role" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/bootstrap/adf-pipeline-check-pipeline-status-lambda" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/bootstrap/adf-pipeline-send-slack-notification-lambda" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/pipeline-management/adf-pipeline-management-codepipeline" + - Sid: "IAMGetOnly" + Effect: "Allow" + Action: + - "iam:GetRole" + - "iam:GetRolePolicy" + Resource: + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf-*" + - !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/adf/*" + - Effect: "Allow" + Action: + - "s3:GetObject" + Resource: + - !Sub "arn:${AWS::Partition}:s3:::${BootstrapTemplatesBucketName}/adf-bootstrap/*" + - !Sub "arn:${AWS::Partition}:s3:::${SharedModulesBucket}/adf-bootstrap/*" + - Effect: "Allow" + Action: + - "codecommit:GetRepository" + Resource: + - !GetAtt CodeCommitRepository.Arn + - Effect: "Allow" + Action: + - "codebuild:BatchGetProjects" + Resource: + - !GetAtt CodeBuildProject.Arn + - !GetAtt PipelineManagementApplication.Outputs.PipelineManagementCodeBuildProjectArn + - Effect: "Allow" + Action: + - "sns:GetTopicAttributes" + Resource: + - !Ref PipelineSNSTopic + - Effect: Allow + Sid: "KickOffPipelineManagement" + Action: + - "states:DescribeExecution" + - "states:StartExecution" + Resource: + - !Sub "arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:stateMachine:adf-bootstrap-enable-cross-account" + - !Sub "arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:execution:adf-bootstrap-enable-cross-account:*" Outputs: ADFVersionNumber: diff --git a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/pipeline_management.yml b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/pipeline_management.yml index c523fe9f6..a9394fb1b 100644 --- a/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/pipeline_management.yml +++ b/src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/pipeline_management.yml @@ -113,6 +113,7 @@ Resources: Type: "AWS::IAM::Role" Properties: Path: "/adf/pipeline-management/" + RoleName: "adf-pipeline-management-deployment-map-processor" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -226,6 +227,7 @@ Resources: Type: "AWS::IAM::Role" Properties: Path: "/adf/pipeline-management/" + RoleName: "adf-pipeline-management-store-pipeline-definition" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -252,6 +254,7 @@ Resources: Type: "AWS::IAM::Role" Properties: Path: "/adf/pipeline-management/" + RoleName: "adf-pipeline-management-identify-out-of-date-pipelines" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -1227,3 +1230,6 @@ Outputs: CreateRepositoryLambdaRoleArn: Value: !GetAtt CreateRepositoryLambdaRole.Arn + + PipelineManagementCodeBuildProjectArn: + Value: !GetAtt PipelineManagementCodeBuildProject.Arn