Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws-codepipeline-actions: Lack of CodePipeline permissions when ECS Resource Tagging Authorization is enabled #25768

Closed
ryo0301 opened this issue May 28, 2023 · 6 comments
Labels
@aws-cdk/aws-codepipeline-actions bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@ryo0301
Copy link

ryo0301 commented May 28, 2023

Describe the bug

When creating a Task definition with tags using EcsDeployAction, I get an error because I don't have ecs:TagResource permission.
(ECS Resource Tagging Authorization is enabled)

Expected Behavior

Task definitions with tags are created without explicitly adding IAM policies

Current Behavior

Need to explicitly allow ecs:TagResource in the IAM role for EcsDeployAction.

User: arn:aws:sts::ACCOUNT:assumed-role/ROLE/SESSION is not authorized to perform: ecs:TagResource on resource: arn:aws:ecs:ap-northeast-1:ACCOUNT:task-definition/TASK_DEF because no identity-based policy allows the ecs:TagResource action",

Even if I allow ecs:TagResource, CodePipeline still fails because I don't have enough permissions in the session policy for AssumeRole.

User: arn:aws:sts::ACCOUNT:assumed-role/ROLE/SESSION is not authorized to perform: ecs:TagResource on resource: arn:aws:ecs:ap-northeast-1:ACCOUNT:task-definition/TASK_DEF because no session policy allows the ecs:TagResource action",

Session policies taken from the Event Record.

    "requestParameters": {
        "roleArn": "arn:aws:iam::ACCOUNT:role/ROLE",
        "roleSessionName": "XXXXXXXXXXXXX",
        "policy": "{\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"ecs:DescribeServices\",\"ecs:DescribeTaskDefinition\",\"ecs:RegisterTaskDefinition\",\"ecs:UpdateService\",\"iam:PassRole\"],\"Resource\":[\"*\"]},{\"Effect\":\"Allow\",\"Action\":[\"s3:GetObject\",\"s3:GetObjectVersion\",\"s3:GetObjectTagging\",\"s3:GetObjectVersionTagging\"],\"Resource\":[\"arn:aws:s3:::BUCKET/PATH\"]},{\"Effect\":\"Allow\",\"Action\":[\"kms:DescribeKey\",\"kms:GenerateDataKey*\",\"kms:Encrypt\",\"kms:ReEncrypt*\",\"kms:Decrypt\"],\"Resource\":[\"*\"]}]}",
        "durationSeconds": 900
    },

Reproduction Steps

Enable ECS Resource Tagging Authorization setting.

aws ecs put-account-setting --name tagResourceAuthorization --value on

Deploy and execute pipeline.

bin/app.ts

#!/usr/bin/env node

import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { MyStack } from "../lib/my-stack";

const app = new cdk.App();
const stack = new MyStack(app, "MyStack", {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION,
  },
});

cdk.Tags.of(stack).add("Key", "Value");

lib/my-stack.ts

import * as cdk from "aws-cdk-lib";
import { BuildSpec, PipelineProject } from "aws-cdk-lib/aws-codebuild";
import { Artifact, Pipeline } from "aws-cdk-lib/aws-codepipeline";
import {
  EcrSourceAction,
  EcsDeployAction,
} from "aws-cdk-lib/aws-codepipeline-actions";
import { Vpc } from "aws-cdk-lib/aws-ec2";
import { Repository } from "aws-cdk-lib/aws-ecr";
import {
  Cluster,
  ContainerImage,
  FargateService,
  FargateTaskDefinition,
} from "aws-cdk-lib/aws-ecs";
import {
  AccountRootPrincipal,
  Effect,
  PolicyDocument,
  PolicyStatement,
  Role,
} from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const repository = new Repository(this, "Repository", {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const taskDefinition = new FargateTaskDefinition(this, "TaskDefinition");
    taskDefinition.addContainer("Container", {
      image: ContainerImage.fromEcrRepository(repository),
    });

    const cluster = new Cluster(this, "Cluster", {
      vpc: Vpc.fromLookup(this, "Vpc", {
        isDefault: true,
      }),
    });
    const service = new FargateService(this, "Service", {
      taskDefinition,
      cluster,
    });

    const sourceArtifact = new Artifact();
    const buildArtifact = new Artifact();

    new Pipeline(this, "DeployPipeline", {
      crossAccountKeys: false,
      stages: [
        {
          stageName: "Source",
          actions: [
            new EcrSourceAction({
              actionName: "PullImage",
              repository: repository,
              output: sourceArtifact,
            }),
          ],
        },
        {
          stageName: "Build",
          actions: [
            new cdk.aws_codepipeline_actions.CodeBuildAction({
              actionName: "PrepareDeploy",
              input: sourceArtifact,
              project: new PipelineProject(this, "BuildSpec", {
                buildSpec: this.buildSpec(),
              }),
              outputs: [buildArtifact],
            }),
          ],
        },
        {
          stageName: "Deploy",
          actions: [
            new EcsDeployAction({
              actionName: "DeployTask",
              service,
              input: buildArtifact,
              role: new Role(this, "DeployRole", {
                assumedBy: new AccountRootPrincipal(),
                inlinePolicies: {
                  deploy: new PolicyDocument({
                    statements: [
                      new PolicyStatement({
                        effect: Effect.ALLOW,
                        actions: ["ecs:TagResource"],
                        resources: ["*"],
                      }),
                    ],
                  }),
                },
              }),
            }),
          ],
        },
      ],
    });
  }

  private buildSpec(): BuildSpec {
    return BuildSpec.fromObject({
      version: "0.2",
      phases: {
        install: {
          "runtime-versions": {
            python: 3.7,
          },
        },
        build: {
          commands: [
            `REPOSITORY_URI=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageURI'].split('@')[0])")`,
            `IMAGE_TAG=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageTags'][0])")`,
            `echo $REPOSITORY_URI:$IMAGE_TAG`,
          ],
        },
        post_build: {
          commands: [
            `printf '[{"name":"Container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json`,
          ],
        },
      },
      artifacts: {
        files: "imagedefinitions.json",
      },
    });
  }
}

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.80.0 (build bbdb16a)

Framework Version

No response

Node.js Version

v18.12.0

OS

macOS 13.3.1 (a)

Language

Typescript

Language Version

TypeScript(5.0.4)

Other information

No response

@ryo0301 ryo0301 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels May 28, 2023
@pahud
Copy link
Contributor

pahud commented May 30, 2023

According to the README here:

it is recommended to provide the role property to the EcsDeployAction. The Role will need to have permissions assigned to it for ECS deployment. See the CodePipeline documentation for the permissions needed.

I believe when you provide the custom role, you will need to attach required permissions to it. Interesting I can't find ecs:TagResource is required in the doc.

@pahud pahud added p2 effort/medium Medium work item – several days of effort response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed effort/medium Medium work item – several days of effort needs-triage This issue or PR still needs to be triaged. labels May 30, 2023
@github-actions
Copy link

github-actions bot commented Jun 1, 2023

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Jun 1, 2023
@ryo0301
Copy link
Author

ryo0301 commented Jun 2, 2023

@pahud ECS Tagging Authorization is a new feature that will become effective gradually by July 17, 2023.

Without the ecs:TagResource permission, the deployment will not work even if it has not been modified.
So I thought it would be better to add it as a default permission for EcsDeployAction.

Also, adding ecs:TagResource to a custom role would not work anyway because it is not added to the session policy during AssumeRole by CodePipeline service.
Might need some additional work on this issue.

@github-actions github-actions bot removed closing-soon This issue will automatically close in 4 days unless further comments are made. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Jun 2, 2023
@ryo0301
Copy link
Author

ryo0301 commented Jun 20, 2023

@pahud I was wondering if there has been any progress on this issue? Your feedback would be greatly appreciated.

@ryo0301
Copy link
Author

ryo0301 commented Jul 16, 2023

At the time of posting this issue, deployments were failing due to the following error, but at this time, perhaps because the CodePipeline service has been modified, the ecs:TagResource privilege is now required at AssumeRole, and the error no longer occurs.
Therefore, this issue is closed.

{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "xxxxxxxxxxxxxx:0000000000",
    "arn": "arn:aws:sts::000000000000:assumed-role/Stack-DeployRoleXXX/0000",
    "accountId": "000000000000",
    "accessKeyId": "XXX",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "principalId": "XXX",
        "arn": "arn:aws:iam::000000000000:role/Stack-DeployRoleXXX",
        "accountId": "000000000000",
        "userName": "Stack-DeployRoleXXX"
      },
      "webIdFederationData": {},
      "attributes": {
        "creationDate": "2023-05-21T16:40:53Z",
        "mfaAuthenticated": "false"
      }
    },
    "invokedBy": "codepipeline.amazonaws.com"
  },
  "eventTime": "2023-05-21T16:40:53Z",
  "eventSource": "ecs.amazonaws.com",
  "eventName": "RegisterTaskDefinition",
  "awsRegion": "ap-northeast-1",
  "sourceIPAddress": "codepipeline.amazonaws.com",
  "userAgent": "codepipeline.amazonaws.com",
  "errorCode": "AccessDenied",
  "errorMessage": "User: arn:aws:sts::000000000000:assumed-role/Stack-DeployRoleXXX/000000000000 is not authorized to perform: ecs:TagResource on resource: arn:aws:ecs:ap-northeast-1:000000000000:task-definition/StackTaskDefinitionXXX because no session policy allows the ecs:TagResource action",
  "requestParameters": null,
  "responseElements": null,
  "requestID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx",
  "eventID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx",
  "readOnly": false,
  "eventType": "AwsApiCall",
  "managementEvent": true,
  "recipientAccountId": "000000000000",
  "eventCategory": "Management"
}

@ryo0301 ryo0301 closed this as completed Jul 16, 2023
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-codepipeline-actions bug This issue is a bug. effort/medium Medium work item – several days of effort p2
Projects
None yet
Development

No branches or pull requests

2 participants