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

CDK Tagging: Stacks dont resolve Tags and autoDeleteObjects in S3 causes Stack level tagging to fail validation #31423

Open
1 task
ryanm101 opened this issue Sep 12, 2024 · 10 comments
Labels
@aws-cdk/aws-s3 Related to Amazon S3 bug This issue is a bug. effort/medium Medium work item – several days of effort p2

Comments

@ryanm101
Copy link

ryanm101 commented Sep 12, 2024

Describe the bug

I see two issues when Tagging at a Stack level.

  1. At the Stack level awsApplication is set to a TOKEN Literal: ${Token[TOKEN.15]}

  2. When create an S3 Resource and setting the autoDeleteObjects property to true I get a validation error. I suspect it is passing the Token Literal OR there is a permission issue.

On Issue 2 using this: Tags.of(this).add('awsApplication', Fn.importValue('AppTag'));
results in

16:39:40 | UPDATE_FAILED        | AWS::IAM::Role                                  | CustomCDKBucketDep...erviceRole89A01265
Resource handler returned message: "1 validation error detected: Value '${Token[TOKEN.16]}' at 'tags.1.member.value' failed to satisfy constraint: Member must satisfy regular expression pattern: [\p{L}\p{Z}\p{N}_.:/=+\-@]* (Service: Iam, Status Code: 400, Request ID: 11111)" (RequestToken: 1, HandlerErr11111
orCode: GeneralServiceException)

Failing at the step: CustomS3AutoDeleteObjectsCustomResourceProviderRole

Using: Tags.of(this).add('awsApplication', Lazy.string({ produce: () => Fn.importValue('AppTag'),}));
Results in:

Received response status [FAILED] from custom resource. Message returned: AccessDenied: User: arn:aws:sts::11111:assumed-role/Frontend-CustomS3AutoDeleteObjectsCusto-6lC587HvLiWH/Frontend-CustomS3AutoDeleteObjectsCust-8PVDc03FABEI is not authorized to perform: s3:GetBucketTagging on resource: "arn:aws:s3:::frontend-undefined8

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

In the case of Number 1: I expect the Stack to be tagged with the ARN passed in.
In the case of Number 2: I expect the Stack to not Fail with a validation error and my bucket get created with the correct tags.

Current Behavior

See Description

Reproduction Steps

#!/usr/bin/env node
import {
  App,
  RemovalPolicy,
  Stack,
  StackProps,
  Tags,
} from "aws-cdk-lib";
import { CfnApplication } from "aws-cdk-lib/aws-servicecatalogappregistry";
import { Construct } from "constructs";
import { BlockPublicAccess, Bucket, BucketEncryption, ObjectOwnership } from 'aws-cdk-lib/aws-s3';

const app = new App();

export class Producer extends Stack {
  public readonly applicationTagValue: string;
  constructor(
    scope: Construct,
    id: string,
    props?: StackProps,
  ) {
    super(scope, id, props);

    // Create an AppRegistry application
    const myApplication = new CfnApplication(this, "CfnApplication", {
      name: "MyApp",
      description: `Core logic for managing MyApp automatically`,
    });

    this.applicationTagValue = myApplication.attrApplicationTagValue;
  }
}

interface ConsumerProps extends StackProps {
  applicationTagValue: string;
}
export class Consumer extends Stack {
  constructor(scope: Construct, id: string, autodeleteobj: boolean, props: ConsumerProps) {
    super(scope, id, props);

    Tags.of(this).add("awsApplication", props.applicationTagValue, {
      excludeResourceTypes: ["AWS::CloudFormation::Stack"],
    });

    const siteBucket = new Bucket(this, 'sitebucket', {
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
      encryption: BucketEncryption.S3_MANAGED,
      versioned: false,
      removalPolicy: RemovalPolicy.DESTROY,
      autoDeleteObjects: autodeleteobj,
    });
  }
}


const producer = new Producer(app, "Producer");

const consumer_TokenLiteral = new Consumer(app, "consumerTokenLiteral", false, {
  applicationTagValue: producer.applicationTagValue,
});

const consumer_ValidationFail = new Consumer(app, "consumerValidationFail", true, {
  applicationTagValue: producer.applicationTagValue,
});

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.158.0 (build 4b8714d)

Framework Version

No response

Node.js Version

Node.js v22.8.0

OS

MacOS (latest)

Language

TypeScript

Language Version

TypeScript 5.5.3

Other information

Slack Thread detailing troubleshooting: https://cdk-dev.slack.com/archives/C018XT6REKT/p1725979817118299

@ryanm101 ryanm101 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Sep 12, 2024
@github-actions github-actions bot added the @aws-cdk/aws-s3 Related to Amazon S3 label Sep 12, 2024
@ryanm101 ryanm101 changed the title (module name): (short issue description) CDK Tagging: Stacks dont resolve Tags and autoDeleteObjects in S3 causes Stack level tagging to fail validation Sep 12, 2024
@gshpychka
Copy link
Contributor

gshpychka commented Sep 12, 2024

Minimal repro for the stack tag resolving to a literal token string. The second stack, if uncommented, fails due to validation of the tag value. Another issue is that excludeResourceTypes is not respected.

import { App, Aws, Stack, StackProps, Tags } from "aws-cdk-lib";
import { StringParameter } from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";

const app = new App();

interface ReproProps extends StackProps {
  tagValue?: string;
}
export class Repro extends Stack {
  public readonly deployTimeValue: string;
  constructor(scope: Construct, id: string, props?: ReproProps) {
    super(scope, id, props);

    this.deployTimeValue = Aws.STACK_ID;

    if (props?.tagValue) {
      Tags.of(this).add("tag", props.tagValue, {
        excludeResourceTypes: ["AWS::CloudFormation::Stack"],
      });
    }

    // stack has to have at least one resource
    const dummyResource = new StringParameter(this, "Default", {
      stringValue: "foo",
    });
  }
}
const producer = new Repro(app, "Producer");

// Will result in the stack having a tag with the value set to `${Token[AWS.StackId.5]}`
const explicitTag = new Repro(app, "ExplicitTag", {
  tagValue: producer.deployTimeValue,
});

// This fails during deployment
//const cdkTag = new Repro(app, "CdkTag", {
//  tags: {
//    tag: producer.deployTimeValue,
//  },
//});
image

@gshpychka
Copy link
Contributor

Relevant? #30515

@ryanm101
Copy link
Author

And 1 more issue is that I suspect that passing that ARN is causing my other stacks to need 'updating' even when there is no change.

@ashishdhingra ashishdhingra self-assigned this Sep 12, 2024
@ashishdhingra ashishdhingra added p2 and removed needs-triage This issue or PR still needs to be triaged. labels Sep 12, 2024
@ashishdhingra
Copy link
Contributor

ashishdhingra commented Sep 12, 2024

@ryanm101 Good afternoon. Thanks for reporting the issue. I tried reproducing the issue using CDK version 2.158.0.

The 1st scenario (for consumer_TokenLiteral) is not reproducible at my end. It creates the the tag properly as shown below:
Screenshot 2024-09-12 at 2 18 53 PM

The 2nd scenario (for consumer_ValidationFail) is reproducible at my end where it fails with the validation error:

2:17:56 PM | CREATE_FAILED        | AWS::IAM::Role              | CustomS3AutoDelete...oviderRole3B1BD092
Resource handler returned message: "1 validation error detected: Value '${Token[TOKEN.35]}' at 'tags.1.member.value' failed to satisfy constraint: Member must satisfy regular expression pattern: [\p{L}\p{Z}\p{N}_.:/=+\-@]* (Service: Iam, Status Code: 400, Request ID: b55bc564-4e8a-4982-99
7b-607afdf04c21)" (RequestToken: a43af8f4-c9be-2523-7a21-fdba6ff976a2, HandlerErrorCode: GeneralServiceException)

It also doesn't work if I change code so that Producer emits CfnOutput and consumer uses it as shown below (with S3 Bucket's autoDeleteObjects set to true):

new cdk.CfnOutput(this, 'attrApplicationTagValue', {
  value: myApplication.attrApplicationTagValue,
  exportName: 'attrApplicationTagValue'
});
...
...
...
cdk.Tags.of(this).add("awsApplication", cdk.Fn.importValue('attrApplicationTagValue'),
{
  excludeResourceTypes: ["AWS::CloudFormation::Stack"],
});

It's failing during creation of AWS::IAM::Role resource CustomS3AutoDeleteObjectsCustomResourceProviderRoleXXXXXXXX. Setting autoDeleteObjects to true makes use of custom resource handler.

Upon searching CDK repo for other related issues, this appears to be similar to #31090, which also has possible reasoning behind it. Could you please check?

Thanks,
Ashish

@gshpychka
Copy link
Contributor

The 1st scenario (for consumer_TokenLiteral) is not reproducible at my end. It creates the the tag properly as shown below:

@ashishdhingra it's reproducible with my repro above

@ryanm101
Copy link
Author

ryanm101 commented Sep 13, 2024

i agree @ashishdhingra issue 2 does look related to #31090

@gshpychka was able to reproduce the Token Literal so I don't think it is just me also per his note there is an issue3 which is that excludeResourceTypes is being ignored as that might produce an acceptable workaround if it could be applied to just the CustomCDK Resource.

Issue 1 was also applied to the consumer_ValidationFail if you look at the stack created even though the resources fail.

@douglascodes
Copy link

douglascodes commented Sep 17, 2024

Experiencing the same error, but on AWS::Lambda::EventSourceMapping. And like @gshpychka says, the excludeResourceTypes does not work.
Removing cdk.Tags.of(this).add("env", envParam.valueAsString); lets it proceed.

1 validation error detected: Value '{env=${Token[TOKEN.25]}}' at 'tags' failed to satisfy constraint: Map value must satisfy constraint: [Member must have length less than or equal to 256, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$] (Service: Lambda, Status Code: 400,

Screenshot at 2024-09-17 13-52-42

@ryanm101
Copy link
Author

I've had the same issue standing up an ALB:
CDK - 2.159.1 (build c66f4e3)

import { Vpc, SubnetType, InstanceType, SecurityGroup, Peer, Port } from 'aws-cdk-lib/aws-ec2';
import { ApplicationLoadBalancer, ApplicationProtocol } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { AutoScalingGroup } from 'aws-cdk-lib/aws-autoscaling';
import { AmazonLinuxImage } from 'aws-cdk-lib/aws-ec2';
import { Stack, StackProps, Tags} from "aws-cdk-lib";
import {Construct} from "constructs";


interface AlbStackProps extends StackProps {
    applicationTagValue: string,
    config: any,
}

export class AlbStack extends Stack {
    public readonly alb: ApplicationLoadBalancer;

    constructor(scope: Construct, id: string, props: AlbStackProps) {
        super(scope, id, props);

        // Tagging fails: https:/aws/aws-cdk/issues/31423 if using CustomVpcRestrictD same as front end issue
        console.log(`[WARN] Stack Tagging disbaled for '${props.config.global.name}-Alb' due to: https:/aws/aws-cdk/issues/31423`)
        //Tags.of(this).add('awsApplication', props.applicationTagValue);

        Tags.of(this).add('Application', props.config.global.name);

        // Create a VPC for the ALB
        const vpc = new Vpc(this, 'MyVPC', {
            maxAzs: 2,
        });

        // Create a security group for the ALB
        const albSecurityGroup = new SecurityGroup(this, 'ALBSecurityGroup', {
            vpc,
            allowAllOutbound: true,
        });
        albSecurityGroup.addIngressRule(Peer.anyIpv4(), Port.tcp(80)); // Allow HTTP traffic to ALB

        // Create an internal ALB
        const alb = new ApplicationLoadBalancer(this, 'MyInternalALB', {
            vpc,
            internetFacing: false, // This makes it internal
            vpcSubnets: {
                subnetType: SubnetType.PRIVATE_WITH_EGRESS, // SubnetType where ALB will live
            },
            securityGroup: albSecurityGroup,
        });

        // Add a listener to the ALB (HTTP)
        const listener = alb.addListener('Listener', {
            port: 80,
            protocol: ApplicationProtocol.HTTP,
        });

        // Auto-scaling group for backend (example for EC2)
        const asg = new AutoScalingGroup(this, 'MyASG', {
            vpc,
            instanceType: new InstanceType('t2.micro'),
            machineImage: new AmazonLinuxImage(),
        });

        // Register the backend instances with the ALB listener
        listener.addTargets('Targets', {
            port: 80,
            targets: [asg],
        });

        this.alb = alb;
    }
}

@ryanm101
Copy link
Author

ryanm101 commented Oct 8, 2024

2.161.1 (build 0a606c9)

I now get: Error: Stack tags may not contain deploy-time values (tag: awsApplication=${Token[TOKEN.17]}). Apply tags containing deploy-time values to resources only, avoid tagging stacks. :/

@gshpychka
Copy link
Contributor

2.161.1 (build 0a606c9)

I now get: Error: Stack tags may not contain deploy-time values (tag: awsApplication=${Token[TOKEN.17]}). Apply tags containing deploy-time values to resources only, avoid tagging stacks. :/

Yup - fixed in #31457.
This issue can be closed as well (the resource type ignore not working probably warrants a separate issue, though)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-s3 Related to Amazon S3 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

4 participants