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

Guidance: NagSuppressions on cdk created stacks #1306

Closed
jgilewski-siili opened this issue May 18, 2023 · 6 comments
Closed

Guidance: NagSuppressions on cdk created stacks #1306

jgilewski-siili opened this issue May 18, 2023 · 6 comments
Labels
guidance Question that needs advice or information.

Comments

@jgilewski-siili
Copy link

jgilewski-siili commented May 18, 2023

What is the problem?

I have a simple stack:

export class EdgeStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    new cloudfront.experimental.EdgeFunction(this, 'EdgeOriginResponseFn', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, '../../../../lambdas/edge-origin-response/dist/function.zip')),
    });
  }
}

Trying to deploy it I got:

[Error at /edge-lambda-stack-c89c9eabf044f7de280376bf016094977ba436a741/EdgeOriginResponseFn/ServiceRole/Resource] AwsSolutions-IAM4[Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]: The IAM user, role, or group uses AWS managed policies. An AWS managed policy is a standalone policy that is created and administered by AWS. Currently, many AWS managed policies do not restrict resource scope. Replace AWS managed policies with system specific (customer) managed policies.This is a granular rule that returns individual findings that can be suppressed with 'appliesTo'. The findings are in the format 'Policy::<policy>' for AWS managed policies. Example: appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/foo'].

I've added:

    NagSuppressions.addResourceSuppressionsByPath(
      this,
      '/edge-lambda-stack-c89c9eabf044f7de280376bf016094977ba436a741/EdgeOriginResponseFn/ServiceRole/Resource',
      [
        {
          id: 'AwsSolutions-IAM4',
          reason: 'CDK managed resource',
          appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
        },
      ]
    );

but the path is not found properly. I got error:

.../node_modules/cdk-nag/src/nag-suppressions.ts:98
    pathArray.forEach((p) => {
              ^
Error: Suppression path "/edge-lambda-stack-c89c9eabf044f7de280376bf016094977ba436a741/EdgeOriginResponseFn/ServiceRole/Resource" did not match any resource. This can occur when a resource does not exist or if a suppression is applied before a resource is created.
    at .../node_modules/cdk-nag/src/nag-suppressions.ts:115:15
    at Array.forEach (<anonymous>)
    at Function.addResourceSuppressionsByPath (.../node_modules/cdk-nag/src/nag-suppressions.ts:98:15)
    at new EdgeStack (.../apps/cloud/src/stacks/edge-stack.ts:25:21)
    at Object.<anonymous> (.../apps/cloud/src/apps/main-app.ts:32:19)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module.m._compile (.../node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Object.require.extensions.<computed> [as .ts] (.../node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1117:32)

I'm not able to suppress this rule.

Reproduction Steps

Full code to reproduce:

import * as path from 'path';

import * as cdk from 'aws-cdk-lib';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';

import { ProjectStackProps } from '../props';

export interface EdgeStackProps extends ProjectStackProps {
  readonly logRetention: logs.RetentionDays;
}

export class EdgeStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    new cloudfront.experimental.EdgeFunction(this, 'EdgeOriginResponseFn', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, '../../../../lambdas/edge-origin-response/dist/function.zip')),
    });

    NagSuppressions.addResourceSuppressionsByPath(
      this,
      '/edge-lambda-stack-c89c9eabf044f7de280376bf016094977ba436a741/EdgeOriginResponseFn/ServiceRole/Resource',
      [
        {
          id: 'AwsSolutions-IAM4',
          reason: 'CDK managed resource',
          appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
        },
      ]
    );
  }
}

What did you expect to happen?

Nag is suppresed.

What actually happened?

Suppression path not found even it is defined.

cdk-nag version

2.27.12

Language

Typescript

Other information

No response

@jgilewski-siili jgilewski-siili added bug Something isn't working needs-triage This issue or PR still needs to be triaged. labels May 18, 2023
@dontirun dontirun added guidance Question that needs advice or information. and removed bug Something isn't working needs-triage This issue or PR still needs to be triaged. labels May 18, 2023
@dontirun
Copy link
Collaborator

I modified the reproduction code a bit and the following worked for me

import * as cdk from 'aws-cdk-lib';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag';


export class EdgeStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    new cloudfront.experimental.EdgeFunction(this, 'EdgeOriginResponseFn', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromInline('foo'),
    });

    NagSuppressions.addResourceSuppressionsByPath(
      this,
      `/${this.stackName}/EdgeOriginResponseFn/Fn/ServiceRole/Resource`,
      [
        {
          id: 'AwsSolutions-IAM4',
          reason: 'CDK managed resource',
          appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
        },
      ]
    );
  }
}
const app = new cdk.App();
new EdgeStack(app, 'test-edge-stack', {env: {region: 'us-east-1'}});
cdk.Aspects.of(app).add(new AwsSolutionsChecks());
app.synth();

@dontirun
Copy link
Collaborator

Are you creating multiple instances of the Stack with different ids? If so the error may be getting thrown on an instance of the stack with a different identifier. I usually use a variable for the stack name to avoid that type of error

@jgilewski-siili
Copy link
Author

Hi @dontirun! Thanks for your quick response. I can see where the problem is. I didn't force the region to be us-east-1.
With my region (which was eu-central-1) the CDK is trying to create an additional stack (that's why the strange name edge-lambda-stack-c89c9eabf044f7de280376bf016094977ba436a741) for some cross-region resources and then the bug persists. Try to deploy your stack from different region.

@dontirun
Copy link
Collaborator

As you noted, the cdk creates a separate stack for certain resources when deployed in eu-central-1. That separate stack is nested under the root application, not the stack that you created. Given that, the following worked for me.

import * as cdk from 'aws-cdk-lib';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag';

export class EdgeStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    new cloudfront.experimental.EdgeFunction(this, 'EdgeOriginResponseFn', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromInline('foo'),
    });
  }
}

const app = new cdk.App();
new EdgeStack(app, 'test-edge-stack', { env: { region: 'eu-central-1' } });
cdk.Aspects.of(app).add(new AwsSolutionsChecks());
// Lookup the cdk created edge stack. Replace the application unique identifier (c81a4702a85c4956cd38c09bdc5df69ed818cefb38) with your own
const cdkEdgeStack = app.node.findChild('edge-lambda-stack-c81a4702a85c4956cd38c09bdc5df69ed818cefb38') as cdk.Stack;
NagSuppressions.addResourceSuppressionsByPath(
  cdkEdgeStack,
  `/${cdkEdgeStack.stackName}/EdgeOriginResponseFn/ServiceRole/Resource`,
  [
    {
      id: 'AwsSolutions-IAM4',
      reason: 'CDK managed resource',
      appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
    },
  ],
);
app.synth();

@jgilewski-siili
Copy link
Author

Thanks @dontirun a lot! That solves my problem.

@dontirun dontirun changed the title bug: NagSuppressions not working for EdgeFunction Guidance: NagSuppressions on cdk created stacks May 20, 2023
@epiphone
Copy link

epiphone commented Nov 8, 2024

Using the root application didn't work for me but cdk.App.of(this) within a Construct did work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
guidance Question that needs advice or information.
Projects
None yet
Development

No branches or pull requests

3 participants