0
votes

I'm trying to set up CodePipeline with an ECS blue/green deployment where the deployment is in a different AWS account.

I've been using the two guides for ECS Blue/Green and CodePipeline cross-account deployments. CodePipeline lives in Account A along with its KMS Key, S3 artifact bucket and ECR repository. The ECS cluster lives in Account B with the CodeDeploy setup.

The ECR, KMS key and S3 buckets have cross-account permissions (these give a different error when wrong). The cluster starts up and runs, and CodeDeploy works correctly when invoked inside Account B.

A role in Account B has been created for CodePipeline to assume and it has granted Account A permission to assume the role. This role currently has the AWSCodeDeployRoleForECS policy (I intend to reduce this once it works)

CodePipeline fails with an unhelpful message of

   "code": "PermissionError",
   "message": "The provided role does not have sufficient permissions to access CodeDeploy"
}```

The codepipeline role does have permission to access codedeploy as it's in the canned AWS policy. I can only assume there's some missing permission but I cannot find out what from this message.
2

2 Answers

4
votes

I've discovered the answer after tracing through CloudTrail. There were two permissions missing from the CodePipeline deployment role which I can't find documented, they are ecs:RegisterTaskDefinition and iam:PassRole for the ECS Container role. CodeDeploy assumes a different role during deployment that also needs these permissions, but it looks like CodePipeline needs them to start the deployment.

The documentation I was working off had an example for CodeDeploy cross-account, but this was CodeDeploy to EC2 rather than to ECS.

My final permissions for the role assumed in Account B by CodePipeline looks like:

{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Action": [
            "codedeploy:CreateDeployment",
            "codedeploy:GetDeployment",
            "codedeploy:GetDeploymentConfig",
            "codedeploy:GetApplicationRevision",
            "codedeploy:RegisterApplicationRevision",
            "codedeploy:GetApplication",
            "ecs:RegisterTaskDefinition"
        ],
        "Resource": "*",
        "Effect": "Allow"
    },
    {
        "Action": [
            "s3:GetObject*",
            "s3:PutObject",
            "s3:PutObjectAcl"
        ],
        "Resource": "arn:aws:s3:::deployment_intermediate_bucket/*",
        "Effect": "Allow"
    },
    {
        "Action": [ "s3:ListBucket"],
        "Resource": "arn:aws:s3:::deployment_intermediate_bucket",
        "Effect": "Allow"
    },
    {
        "Effect": "Allow",
        "Action": [
            "kms:DescribeKey",
            "kms:GenerateDataKey*",
            "kms:Encrypt",
            "kms:ReEncrypt*",
            "kms:Decrypt"
        ],
        "Resource": [
            "deployment_kms_key_arn"
        ]
    },
    {
        "Action": [
            "iam:PassRole"
        ],
        "Effect": "Allow",
        "Resource": "ecs_container_role_arn"
    }
  ]
}

I'm going to reduce this down to the minimum required.

0
votes

To maybe help here, having had the same issue/error:

Using Cloud-formation, I have a pipeline in account a, with an ecs bluegreen action in account b (TestingAccount):

        - Name: !Sub BlueGreenDeploy
          Actions:
            - Name: BlueGreenDeploy
              InputArtifacts:
              # - Name: PrepareCodeDeployOutput
              - Name: !Ref SourceArtifactName
              Region: !Ref DeployRegion1
              ActionTypeId:
                Category: Deploy
                Owner: AWS
                Version: '1'
                Provider: CodeDeployToECS
              RoleArn: !Sub arn:aws:iam::${TestingAccountId}:role/######/CrossAccountsDeploymentRole
              Configuration:

                AppSpecTemplateArtifact: !Ref SourceArtifactName
                AppSpecTemplatePath: appspec.json

                ApplicationName: ronantest1
                DeploymentGroupName: ronantest1
                
                TaskDefinitionTemplateArtifact: !Ref SourceArtifactName
                TaskDefinitionTemplatePath: taskdef.json

                Image1ArtifactName: !Ref SourceArtifactName
                Image1ContainerName: "IMAGE1_NAME"
              RunOrder: 4

In the task definition that I was trying to deploy, I had the following roles listed:

    "taskRoleArn"
    "executionRoleArn"

The role that the pipeline assumed in the target account, i.e:

   arn:aws:iam::${TestingAccountId}:role/######/CrossAccountsDeploymentRole

It needed to be able to pass both those roles listed in the Task definition.

Hope that makes sense and helps. AWS does not make this stuff easy from their documentation.