stelligent / cfn_nag

Linting tool for CloudFormation templates
MIT License
1.25k stars 209 forks source link

W58 violation invalid #572

Closed udaykirankavaturu closed 2 years ago

udaykirankavaturu commented 2 years ago

Hi,

I have a stack for that has a role with an attached managed policy, which has all access to cloudwatch and logs. I am assigning this role to a lambda and 'synth'ing it with cdk synth.

But cfn nag scan always shows W58 Lambda functions require permission to write CloudWatch Logs.

Below is my code snippet. What am I doing wrong?

`export class cfnAnalytics extends cdk.Stack {

constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const key = new kms.Key(this, "MyKey",{
        enableKeyRotation: true
    });
    const dataStream = new Stream(this, "event-stream", {
        // streamName: common.envSpecificName(analyticsEnv.streamName),
        encryption: StreamEncryption.KMS,
        encryptionKey: key
    });

    // Analytics lambda functions
    this.putEvent(dataStream);
}

/**
 * Defining send events data lambda function
 */
putEvent(dataStream: any) {
    const cloudWatchPolicy = common.envSpecificName(managedPolicyEnv.cloudWatchPolicy);
    const kinesisPolicy = common.envSpecificName(managedPolicyEnv.kinesisPolicy);
    const role = new iam.Role(this, 'putEventRole', {
        assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
        managedPolicies: [
            iam.ManagedPolicy.fromManagedPolicyName(this, 'analyticsCloudWatchPolicy', Fn.importValue(cloudWatchPolicy)),
            iam.ManagedPolicy.fromManagedPolicyName(this, 'analyticsKinesisPolicy', Fn.importValue(kinesisPolicy))
        ],
    })

    new lambda.Function(this, common.envSpecificName('put-event'), {
        functionName: common.envSpecificName("mobrush_analytics_put_event"),
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'index.handler',
        code: lambda.Code.fromAsset('src/analytics/put-data'),
        role,
        environment: {
            STREAM_NAME: dataStream.streamName
        },
        reservedConcurrentExecutions: 10
    });
}

}`

udaykirankavaturu commented 2 years ago

my role and lambda are in this template.. but the policy is from another stack. however I tried to attach the same policy separately to the role in this stack as well.. but cfn_nag_scan doesn't seem to recognize any policy.

SchnitzelKopf commented 2 years ago

Having a similar problem with native CFN. Role + Policy even is in the same stack.

AWSTemplateFormatVersion: '2010-09-09'
Description: Deploys Lambdas for RDS. (CheckIfRDSIsStopped)
Parameters:
  S3LambdaPath:
    Description: Path to S3 Object including Lambda zip files.
    Type: String
    Default: lambda/RDS/backend
    MinLength: '1'
    MaxLength: '50'
Resources:
  CheckIfRDSIsStoppedLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: CheckIfRDSIsStoppedLambdaExecutionRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        # https://docs.aws.amazon.com/mediaconnect/latest/ug/iam-policy-examples-asm-secrets.html
        - PolicyName: CheckIfRDSIsStoppedLambdaExcecutionPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                # enable access to check if RDS is running or stopped
                Action:
                  - rds:DescribeDBInstances
                Resource: '*'
              - Effect: Allow
                # enable to write logs
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:FilterLogEvents
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:* 
              - Effect: Allow
                # enable to describeStacks
                Action:
                  - cloudformation:DescribeStacks
                Resource: '*' 

  CheckIfRDSIsStoppedLambda:
    Type: AWS::Lambda::Function
    Properties:
      Description: Returns warning if RDS is stopped. Informs about Service Actions (start RDS).
      Code:
        S3Bucket: !Sub '${AWS::AccountId}-s2-central-sources'
        S3Key: !Join
          - ''
          - - !Ref 'S3LambdaPath' #lambda/RDS/backend
            - /CheckIfRDSIsStopped.zip
      FunctionName: ABCD-CheckIfRDSIsStopped
      Layers:
        # ABCD-crhelperLayer
        - !Sub arn:aws:lambda:eu-central-1:${AWS::AccountId}:layer:ABCD-crhelperLayer:2
      Handler: CheckIfRDSIsStopped.handler
      MemorySize: 128
      Timeout: 30
      Role: !Sub '${CheckIfRDSIsStoppedLambdaExecutionRole.Arn}'
      Runtime: python3.8
      Tags:
        - Key: ApplicationName
          Value: ABCD
        - Key: CostReference
          Value: '{{resolve:ssm:/ABCD/Customers/ABCD/CostReference}}'
        - Key: Name
          Value: ABCD-CheckIfRDSIsStopped
        - Key: Description
          Value: Warns if RDS is stopped.
udaykirankavaturu commented 2 years ago

my role and lambda are in this template.. but the policy is from another stack. however I tried to attach the same policy separately to the role in this stack as well.. but cfn_nag_scan doesn't seem to recognize any policy.

I actually understood why this is happening. nag_scan can only see what's available in the template. It cannot look inside a managed policy and determine what permissions are available.

So it's better to use inline policies wherever possible, like this:

inlinePolicies: { "cloudwatchLogs": new iam.PolicyDocument({ statements: [ new iam.PolicyStatement({ actions: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ], effect: iam.Effect.ALLOW, resources: [arn:aws:lambda:::function*] }) ] }) }

Side note:

When I looked at the ruby code of the cfn_nag_scan tool itself, it is passing this rule if one of the AWS managed policies is used along with the role.

So in my case, I was able to break another violation on VPC by using this AWS managed policy instead of an inline policy --> AWSLambdaVPCAccessExecutionRole

I used this line to pass it to the role: iam.ManagedPolicy.fromManagedPolicyArn(this, 'VPC Access', "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole")

these policies provide the required access to * resources.