question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

bug: IAM5 resource based granular suppressions need better serialisation

See original GitHub issue

What is the problem?

The resource based rule findings for the IAM5 rule come out as [object Object] when the resource ARNs are complex.

Example:

[Error at /thglaser-ldn-mainline/api/apiHandlerRole/Resource] AwsSolutions-IAM5[Resource::[object Object]]: The IAM entity contains wildcard permissions and does not have a cdk_nag rule suppression with evidence for those permission.

Reproduction Steps

Create a policy that constructs the ARN based on some inputs like so:

export interface LambdaBaseRoleProps {
  functionName: string;
}

export class LambdaBaseRole extends Role {
  constructor(scope: IConstruct, id: string, props: LambdaBaseRoleProps) {
    super(scope, id, {
      assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
      inlinePolicies: {
        logAccess: new PolicyDocument({
          statements: [
            new PolicyStatement({
              actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
              resources: [
                Stack.of(scope).formatArn({
                  service: 'logs',
                  resource: 'log-group',
                  resourceName: `/aws/lambda/${props.functionName}`,
                  arnFormat: ArnFormat.COLON_RESOURCE_NAME,
                }),
                Stack.of(scope).formatArn({
                  service: 'logs',
                  resource: 'log-group',
                  resourceName: `/aws/lambda/${props.functionName}:log-stream:*`,
                  arnFormat: ArnFormat.COLON_RESOURCE_NAME,
                }),
              ],
            }),
          ],
        }),
      },
    });

    NagSuppressions.addResourceSuppressions(
      this,
      [
        // {
        //   id: 'AwsSolutions-IAM5',
        //   reason: 'The resource is scoped down to relevant log streams',
        // },
      ],
      true,
    );
  }
}

What did you expect to happen?

Anything but [object Object] as it makes it impossible to suppress a specific resource

What actually happened?

(see problem description)

cdk-nag version

2.7.0

Language

Typescript

Other information

I have a sketch of a fix in my mind. It would be ideal if the resource object could be flattened so that I can granularly suppress.

Consider the following function:

const flattenCfn = (node: any): string {
  if (typeof node === 'string') {
    return node
  }
  if (node["Fn::Join"]) {
    const delimiter = node["Fn::Join"][0];
    const items = node["Fn::Join"][1]
    return items.map(flattenCfn).join(delimiter)
  }

  if (node['Fn::Sub']) {
    return flattenCfn(node['Fn::Sub'])
  }

  if (node['Fn::GetAtt']) {
    return "${" + flattenCfn(node['Fn::GetAtt'][0]) + "." + flattenCfn(node['Fn::GetAtt'][1]) + "}"
  }

  if (node['Fn::ImportValue']) {
    return flattenCfn(node['Fn::ImportValue'])
  }

  if (node['Ref']) {
    return "${" + flattenCfn(node['Ref']) + "}"
  }

  return JSON.stringify(node)
}

The function would turn this:

{
  "Fn::Join": [
    "",
    [
      "arn:",
      {
        "Ref": "AWS::Partition"
      },
      ":s3:::",
      {
        "Fn::Sub": "cdk-62b12fb5cc-assets-${AWS::AccountId}-eu-west-2"
      },
      "/*"
    ]
  ]
}

into this

"arn:${AWS::Partition}:s3:::cdk-62b12fb5cc-assets-${AWS::AccountId}-eu-west-2/*"

which would be much easier to suppress than [object Object].

I’d be happy to contribute a PR to that effect.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5

github_iconTop GitHub Comments

1reaction
tkglasercommented, Feb 25, 2022

Ah I see! I’m not super familiar with jsii, are there restrictions for the internal code too, like can I use the JavaScript RegExp class inside of the rules engine?

Edit: Nevermind, you already answered that in your original message. 😁

Ok, sounds good, I’ll start working on that PR!

1reaction
dontiruncommented, Feb 25, 2022

I like the regex idea and I think it would also simplify suppressions of similar findings.

How about we allow regexes in the appliesTo? Like this:

While we can use any TypeScript related feature on the backend, our public APIs need to work across languages. Fortunately jsii allows us to use interfaces and will generate language specific bindings to use that API. Your suggested hint for CloudFormation is probably how we want to structure the interface.

/**
 * Interface for creating a rule suppression
 */
export interface NagPackSuppression {
  /**
   * The id of the rule to ignore
   */
  readonly id: string;
  /**
   * The reason to ignore the rule (minimum 10 characters)
   */
  readonly reason: string;
  /**
   * Rule specific granular suppressions
   */
  readonly appliesTo?: (string | RegexAppliesTo)[];
}

/**
 * A regular expression to apply to matching findings
 */
export interface RegexAppliesTo {
  /**
   * An ECMA-262 regex string
   */
  readonly regex: string;
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found