Static Analysis for CloudFormation
Tags: aws, cloudformation, cfnlint, cfnnag
Published: 2021-12-29 17:38:27

To satisfy CloudFormation is well, we should apply static analysis tool for it.
Today, I would like 2 static analysis tools:
- [cfn-lint](https://github.com/aws-cloudformation/cfn-lint): Verify that the template is correct.
- [cfn-nag](https://github.com/stelligent/cfn_nag): Verify that there is no code that poses a security risk.

## Sections
- [Setup](#setup)
- [cfn-lint Usage](#cfnlint-usage)
- [cfn_nag Usage](#cfnnag-usage)

## Setup

- cfn-lint
```bash
pip install cfn-lint
```

- cfn_nag
```bash
gem install cfn-nag
```

- setup cloudformation template with name s3.yml
```yml
AWSTemplateFormatVersion: '2010-09-09'

Description: S3 Cloudformation Template

Parameters:
  
  EnvironmentStage: 
    AllowedValues:
      - "Dev"
      - "Stg"
      - "Prod"
    Default: "Dev"
    Description: "Environment Dev, Staging, Production"
    Type: String

Resources:

  WebCmsOAI:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: Origin Access Identity for Web Cms S3 Bucket

  WebCmsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub '${AWS::StackName}-web-cms'
      CorsConfiguration:
        CorsRules:
        - AllowedHeaders:
          - '*'
          AllowedMethods:
          - GET
          - PUT
          AllowedOrigins:
          - '*'
          MaxAge: 3000
      VersioningConfiguration:
        Status: Enabled
      WebsiteConfiguration:
        ErrorDocument: index.html
        IndexDocument: index.html

  WebCmsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    DependsOn: WebCmsBucket
    Properties:
      Bucket: !Ref WebCmsBucket
      PolicyDocument:
        Statement:
          - Action:
              - 's3:GetObject'
            Effect: Allow
            Resource: !Sub 'arn:aws:s3:::${AWS::StackName}-web-cms/*'
            Principal: 
              CanonicalUser: !GetAtt WebCmsOAI.S3CanonicalUserId

Outputs:
  WebCmsBucket:
    Value: !Ref WebCmsBucket
    Export:
      Name: !Sub '${AWS::StackName}-WebCmsBucket'

  WebCmsBucketEndpoint:
    Value: !Join
      - ''
      - - !GetAtt
           - WebCmsBucket
           - RegionalDomainName
    Export:
      Name: !Sub '${AWS::StackName}-WebCmsBucketEndpoint'

  WebCmsOAI:
    Value: !Ref WebCmsOAI
    Export:
      Name: !Sub ${AWS::StackName}-WebCmsOAI

```

## cfn-lint Usage
```bash
> cfn-lint s3.yml
W2001 Parameter EnvironmentStage not used.
s3.yml:7:3

W3005 Obsolete DependsOn on resource (WebCmsBucket), dependency already enforced by a "Ref" at Resources/PublicCMSWebsitePolicy/Properties/Bucket/Ref
s3.yml:46:5
```
As you can see, cfn-lint output covers all 2 issues that we previously highlighted in the form of warnings and errors. Errors indicate issues that will prevent your CloudFormation stack from deploying, and warnings indicate potential issues in your stack that you might want to think about.

cfn-lint also comes with extensive configuration support which allows you to customise your linting rules.
```yml
WebCmsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    DependsOn: WebCmsBucket
    Properties:
      Bucket: !Ref WebCmsBucket
      PolicyDocument:
        Statement:
          - Action:
              - 's3:GetObject'
            Effect: Allow
            Resource: !Sub 'arn:aws:s3:::${AWS::StackName}-web-cms/*'
            Principal: 
              CanonicalUser: !GetAtt WebCmsOAI.S3CanonicalUserId
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - W3005
```

## cfn_nag Usage
```bash
> cfn_nag_scan -i s3.yml
------------------------------------------------------------
s3.yml
------------------------------------------------------------------------------------------------------------------------
| WARN W35
|
| Resource: ["WebCmsBucket"]
| Line Numbers: [25]
|
| S3 Bucket should have access logging configured
------------------------------------------------------------
| WARN W41
|
| Resource: ["WebCmsBucket"]
| Line Numbers: [25]
|
| S3 Bucket should have encryption option set

Failures count: 0
Warnings count: 2
```
As you can see, cfn_nag output covers all 2 issues that we previously highlighted in the form of warnings and failures. These issues that will prevent your CloudFormation stack from security risks

cfn_nag also comes with extensive configuration support which allows you to customise your rules.
```yml
WebCmsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub '${AWS::StackName}-web-cms'
      CorsConfiguration:
        CorsRules:
        - AllowedHeaders:
          - '*'
          AllowedMethods:
          - GET
          - PUT
          AllowedOrigins:
          - '*'
          MaxAge: 3000
      VersioningConfiguration:
        Status: Enabled
      WebsiteConfiguration:
        ErrorDocument: index.html
        IndexDocument: index.html
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W35
            reason: "Test ignore rule S3 Bucket should have access logging configured"
          - id: W41
            reason: "Test ignore rule S3 Bucket should have encryption option set"
```