Skip to content

Tool Is Not Transforming SAM (AWS::Serverless-2016-10-31) Correctly #522

@chrisoverzero

Description

@chrisoverzero

Given the following reduced test template:

---
AWSTemplateFormatVersion: 2010-09-09

Transform: AWS::Serverless-2016-10-31

Description: A reduced test template.

Globals:
  Api:
    OpenApiVersion: '3.0.1'
    AccessLogSetting:
      Format: $context.requestId
    Auth:
      UsagePlan:
        CreateUsagePlan: PER_API

Resources:
  Http:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: nodejs14.x
      Handler: index.default
      InlineCode: |-
        exports.default = () => { }
      Events:
        ProxyApi:
          Type: Api
          Properties:
            Method: ANY
            Path: /{proxy+}

cfn_nag reports the following:

------------------------------------------------------------
./template.yml
------------------------------------------------------------------------------------------------------------------------
| WARN W68
|
| Resources: ["ServerlessRestApiDeployment"]
| Line Numbers: [-1]
|
| AWS::ApiGateway::Deployment resources should be associated with an AWS::ApiGateway::UsagePlan. 
------------------------------------------------------------
| WARN W69
|
| Resources: ["ServerlessRestApiProdStage"]
| Line Numbers: [-1]
|
| AWS::ApiGateway::Stage should have the AccessLogSetting property defined.
------------------------------------------------------------
| WARN W64
|
| Resources: ["ServerlessRestApiProdStage"]
| Line Numbers: [-1]
|
| AWS::ApiGateway::Stage resources should be associated with an AWS::ApiGateway::UsagePlan. 

Failures count: 0
Warnings count: 3

These associations and property do exist, however. When transformed by SAM, the template produced is this:

The transformed template is kinda verbose.
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "A reduced test template.",
  "Resources": {
    "Http": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "ZipFile": "exports.default = () => { }"
        },
        "Handler": "index.default",
        "Role": {
          "Fn::GetAtt": [
            "HttpRole",
            "Arn"
          ]
        },
        "Runtime": "nodejs14.x",
        "Tags": [
          {
            "Key": "lambda:createdBy",
            "Value": "SAM"
          }
        ]
      }
    },
    "HttpRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              }
            }
          ]
        },
        "ManagedPolicyArns": [
          "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
        ],
        "Tags": [
          {
            "Key": "lambda:createdBy",
            "Value": "SAM"
          }
        ]
      }
    },
    "HttpProxyApiPermissionProd": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "Http"
        },
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {
          "Fn::Sub": [
            "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/*",
            {
              "__ApiId__": {
                "Ref": "ServerlessRestApi"
              },
              "__Stage__": "*"
            }
          ]
        }
      }
    },
    "ServerlessRestApi": {
      "Type": "AWS::ApiGateway::RestApi",
      "Properties": {
        "Body": {
          "info": {
            "version": "1.0",
            "title": {
              "Ref": "AWS::StackName"
            }
          },
          "paths": {
            "/{proxy+}": {
              "x-amazon-apigateway-any-method": {
                "x-amazon-apigateway-integration": {
                  "type": "aws_proxy",
                  "httpMethod": "POST",
                  "uri": {
                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Http.Arn}/invocations"
                  }
                },
                "responses": {}
              }
            }
          },
          "openapi": "3.0.1"
        }
      }
    },
    "ServerlessRestApiDeployment7a650ad703": {
      "Type": "AWS::ApiGateway::Deployment",
      "Properties": {
        "Description": "RestApi deployment id: 7a650ad703b8db9ec385abf58d5a42934aa71554",
        "RestApiId": {
          "Ref": "ServerlessRestApi"
        }
      }
    },
    "ServerlessRestApiProdStage": {
      "Type": "AWS::ApiGateway::Stage",
      "Properties": {
        "AccessLogSetting": {
          "Format": "$context.requestId"
        },
        "DeploymentId": {
          "Ref": "ServerlessRestApiDeployment7a650ad703"
        },
        "RestApiId": {
          "Ref": "ServerlessRestApi"
        },
        "StageName": "Prod"
      }
    },
    "ServerlessRestApiUsagePlan": {
      "Type": "AWS::ApiGateway::UsagePlan",
      "DependsOn": [
        "ServerlessRestApi"
      ],
      "Properties": {
        "ApiStages": [
          {
            "ApiId": {
              "Ref": "ServerlessRestApi"
            },
            "Stage": {
              "Ref": "ServerlessRestApiProdStage"
            }
          }
        ]
      }
    },
    "ServerlessRestApiApiKey": {
      "Type": "AWS::ApiGateway::ApiKey",
      "DependsOn": [
        "ServerlessRestApiUsagePlan"
      ],
      "Properties": {
        "Enabled": true,
        "StageKeys": [
          {
            "RestApiId": {
              "Ref": "ServerlessRestApi"
            },
            "StageName": {
              "Ref": "ServerlessRestApiProdStage"
            }
          }
        ]
      }
    },
    "ServerlessRestApiUsagePlanKey": {
      "Type": "AWS::ApiGateway::UsagePlanKey",
      "DependsOn": [
        "ServerlessRestApiApiKey"
      ],
      "Properties": {
        "KeyId": {
          "Ref": "ServerlessRestApiApiKey"
        },
        "KeyType": "API_KEY",
        "UsagePlanId": {
          "Ref": "ServerlessRestApiUsagePlan"
        }
      }
    }
  }
}

When scanned, this produces no warnings or failures:

------------------------------------------------------------
./template.processed.json
------------------------------------------------------------
Failures count: 0
Warnings count: 0

This was run via the Docker image stelligent/cfn_nag:latest.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions