Securing Cross-Account Access for CodePipeline

0

I'm using CodePipeline to deploy code from my development account to my application account using cross-account deployment techniques describe on the following page:

https://aws.amazon.com/premiumsupport/knowledge-center/codepipeline-deploy-cloudformation/

I have a cross-account role that is deployed in the deployment target accounts via a CloudFormation as follows:

  CrossAccountDeploymentRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Service:
                - 'cloudformation.amazonaws.com'
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess'
      RoleName: 'CrossAccountDeploymentRole'

It seems to me that this grant is overpermissive and would allow someone who knew the account number and role name to assume this role via a cross-account CloudFormation stack deployment from their own account. Essentially, there's nothing here that says "only let CloudFormation assume this role if the request is from account number 123456789012".

How can I limit this role such that CloudFormation is only allowed to assume this role if it is being called from a specific AWS account?

3 Answers
1

The configuration you describe provides the service role that CloudFormation uses to execute the change set or deploy the stack. You still have to have permissions to pass the role to CloudFormation (iam:PassRole) on a per stack basis and create the stack itself. See here. You can only pass the role from an IAM role in the same account. So, if I'm trying to create a stack and specify a role in a different account, the stack creation will fail because I can't pass that role to CFN. If you look at the instructions here and here, you'll see that the cross account access relies on a role in Account A where the pipeline lives assuming a role in Account B. Then it uses the role in Account B to create the stack and to pass a third role to CFN, also in Account B. This prevents any type of cross account access with the role that trusts the CloudFormation service principal (cloudformation.amazonaws.com).

AWS
mike
answered 2 years ago
  • The role I described is deployed in account B. Account A assumes this role during a CodePipeline deployment via a CloudFormation deployment. The pipeline does have the ability to sts:AssumeRole the role in account B. This already works, and is not my question. My question is that the role in Account B does not know anything about account A. How do I tell account B to only allow the role to be assumed by CloudFormation when it's called from a CodePipeine executing in account A?

  • Per @mike's description, you will have 2 roles in Account B - 1/ cross-account role that CodePipeline will assume 2/ service role that will be passed to CloudFormation and deploy the resources. Cross-account role is the one that has permissions to pass the service role to CloudFormation for Account B. This is also the only role that can trigger the deployment in Account B. In order to prevent from another account to use the cross-account role, you can specify Account A as the only approved principal in role's trust policy.

  • You said "you can specify Account A as the only approved principal in role's trust policy", which is exactly what I'm trying to do. What's the magic incantation to make that happen?

1

Hi! Good question. I'm reviewing the 2 answers above, and don't think they solve what you're trying to do.

In this case, you would want to limit access via the role you have in Account B - and to do so, you would have to do so on the IAM Role's trust relationship to scope that down so AWS is not using CloudFormation as a confused deputy.

Check out the IAM Condition Key aws:SourceAccount: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-sourceaccount. I'm not sure if this works with CodePipeline, but that condition would do what you are looking to do: "This key is included in the request context only if accessing a resource triggers an AWS service to call another service on behalf of the resource owner. The calling service must pass the resource account ID of the source to the called service. This account ID includes the source account ID."

aws:PrincipalOrgID would not be applicable to the trust policy you have posted above, since the trusted principal is the AWS Service, cloudformation.amazonaws.com.

jsonc
answered 2 years ago
  • Yes, I think aws:SourceAccount is what I'm looking for. Where can I find whether or not CodePipeline and/or CloudFormation include this in the cross-account request?

0

If you're using AWS Organizations you can use IAM Condition Keys, such as aws:PrincipalOrgID, to help craft a more specific scoped policy on who (or what) can assume a role. In the case of wanting to ensure only principals from within your organization are able to assume a role. You can also build the IAM role/policy with a condition (or specific ARN depending on how prescriptive you want to be) which only allows assuming a role from a single known account or even a single role in a single account.

AWS
answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions