Supply Chain

Secure AWS CloudFormation Templates with cnspec

Scan AWS CloudFormation templates for security misconfigurations with cnspec.

import IacScanOptions from './_iac-scan-options.mdx';

Catch insecure AWS resource configurations before they reach a stack. cnspec parses both YAML and JSON CloudFormation templates and exposes resources, parameters, outputs, and other template sections as queryable MQL resources. The Mondoo AWS Security policy ships CloudFormation variants of every check, so the same controls that evaluate your live AWS account also evaluate your CloudFormation templates in pull requests and CI pipelines. You can also use the CloudFormation provider inside your own policies to enforce additional standards.

Prerequisites

To scan CloudFormation templates with cnspec, you must have:

Scan a CloudFormation template

Scan a single template file:

cnspec scan cloudformation template.yaml

cnspec automatically detects whether the template is YAML or JSON.

Explore CloudFormation templates

Run cnspec shell cloudformation template.yaml to open the interactive shell and explore your templates.

Retrieve template info

cnspec> cloudformation.template { version description }
cloudformation.template: {
  version: "2010-09-09"
  description: "Production infrastructure stack"
}

List all resources

cnspec> cloudformation.template.resources
cloudformation.template.resources: [
  0: cloudformation.resource type="AWS::EC2::Instance"
  1: cloudformation.resource type="AWS::S3::Bucket"
  ...
]

Retrieve resource details

cnspec> cloudformation.template.resources { name type properties }
cloudformation.template.resources: [
  0: {
    name: "WebServer"
    type: "AWS::EC2::Instance"
    properties: {
      InstanceType: "t3.micro"
      ImageId: "ami-0abcdef1234567890"
    }
  }
  ...
]

Filter resources by type

Find all S3 bucket resources:

cnspec> cloudformation.template.resources.where(type == "AWS::S3::Bucket") { name properties }
cloudformation.template.resources.where: [
  0: {
    name: "DataBucket"
    properties: {
      BucketName: "my-data-bucket"
      VersioningConfiguration: {
        Status: "Enabled"
      }
    }
  }
]

List all resource types used in the template:

cnspec> cloudformation.template.types
cloudformation.template.types: [
  0: "AWS::EC2::Instance"
  1: "AWS::S3::Bucket"
  2: "AWS::IAM::Role"
  ...
]

Inspect template parameters

cnspec> cloudformation.template.parameters
cloudformation.template.parameters: {
  InstanceType: {
    Type: "String"
    Default: "t3.micro"
    AllowedValues: ["t3.micro", "t3.small", "t3.medium"]
  }
  Environment: {
    Type: "String"
    Default: "production"
  }
  ...
}

List template outputs

cnspec> cloudformation.template.outputs { name properties }
cloudformation.template.outputs: [
  0: {
    name: "InstanceId"
    properties: {
      Description: "The instance ID"
      Value: {"Ref": "WebServer"}
    }
  }
  ...
]

Retrieve conditions

cnspec> cloudformation.template.conditions
cloudformation.template.conditions: {
  IsProduction: {
    "Fn::Equals": [{"Ref": "Environment"}, "production"]
  }
  ...
}

Retrieve mappings

cnspec> cloudformation.template.mappings
cloudformation.template.mappings: {
  RegionMap: {
    us-east-1: {
      AMI: "ami-0abcdef1234567890"
    }
    us-west-2: {
      AMI: "ami-0fedcba9876543210"
    }
  }
  ...
}

Get full template details

cnspec> cloudformation.template { * }

Example security checks

Ensure EC2 instances don't use a hardcoded AMI

cloudformation.template.resources.where(type == "AWS::EC2::Instance").all(
  properties["ImageId"] != /^ami-/
)

Check that no security groups allow unrestricted SSH

cloudformation.template.resources.where(type == "AWS::EC2::SecurityGroup") {
  name
  properties["SecurityGroupIngress"]
}

Learn more

On this page