Skip to content

Commit

Permalink
Fix deployment bootstrap IAM PassRole permissions
Browse files Browse the repository at this point in the history
Issue: awslabs#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.
  • Loading branch information
sbkok committed Oct 25, 2024
1 parent 5178240 commit a52ded3
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -1786,7 +1824,7 @@ Resources:
Action:
- sts:AssumeRole
Policies:
- PolicyName: "limited-update-permissions-only"
- PolicyName: "limited-update-permissions-only-part1"
PolicyDocument:
# Please note, that some of the resources are intentionally
# left out of scope for the update deployment role.
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -1227,3 +1230,6 @@ Outputs:

CreateRepositoryLambdaRoleArn:
Value: !GetAtt CreateRepositoryLambdaRole.Arn

PipelineManagementCodeBuildProjectArn:
Value: !GetAtt PipelineManagementCodeBuildProject.Arn

0 comments on commit a52ded3

Please sign in to comment.