The core linting of cfn-lint
is based on the CloudFormation resource provider schemas. The AWS CloudFormation resource provider schemas are JSON documents that describe the shape of a resource, what actions are supported, and permissions for that resource to function. More info
Resource provider schemas are based on JSON Schema and include modifications for the service to work with CloudFormation.
There are multiple rules that are based on information from the specification files. Every keyword in the draft-07 are accounted for by cfn-lint. In a lot of scenarios we will remap those validators to cfn-lint rule IDs so the rules can be suppressed as needed.
To improve the experience of validation we have made modifications to standard JSON schema so that it works better with CloudFormation.
CloudFormation allows types to work interchangeably as long as a conversion can be done (Example: "10" and 10 are equivalent). As a result we have modified type checking to validate the values are of the right type.
CloudFormation allows for a value of a property to be {"Ref": "AWS:NoValue"}
which is equivalent to that property not being specified. JSON schema validators that work on a set of properties (object or array) are validated after the properties have been cleaned of these no values. This will allow validators like required and dependencies to work as intended.
When resource provider schemas are created they do not account for CloudFormation intrinsic functions. cfn-lint will account for these intrinsic functions by validating the structure of the function. Additionally, if possible, the value will be resolved (Example: {"Ref": "AWS::Region"}
will resolve to "us-east-1") and that value will be validated against the schema.
Certain resource properties represent a type that is common across many resource types (example: availaibility zones, AMIs, VPCs, IAM identity policies, etc.). To provide common validation of these types we have extended the resource provider schemas with a type of awsType
the value for the keyword is the type name. For a list of supported types go here.
Resource types may have complex rules to define what a valid resource configuration is (example: for RDS the properties you need to specify can change based on the engine and if you are restoring from a snapshot). cfn-lint extends the resource provider schema with the keyworkd cfnLint
which will validate the appropriate level against additional schema documents. This mechanism allows cfn-lint rule writers to create a new rule ID for these additional schemas which then allow users of cfn-lint to disable these validations as needed.
To make schema writing easier across hundereds of resources we have extend the schemas to include some additional keywords. While these keywords can be covered under the JSON schema they have to be done with a combination of if
s, onlyOne
s, anyOf
s, etc. By using these keywords we can extend the schema for common scenarios when writing CloudFormation schemas.
type specifies the data type for a schema. JSON Schema docs
enum is used to restrict a value to a fixed set of values. JSON Schema docs
pattern keyword is used to validate a string against a regular expression. JSON Schema docs
minLength and maxLength are used to are used to constrain the size of a string. JSON Schema docs
minimum and maximum is used to define the inclusive range for a number or integer. exclusiveMinimum and exclusiveMaximum is used to define the exlusive range for a number or integer.
minItems and maxItems is used to provide the inclusive length of an array.
prefixItems is similar to the definition of prefixItems but doesn't actually do the prefix. The current resource schema doesn't support items being an array. We use prefixItems
to validate array items where ordering matters.
properties provides the key names and a value that represents the schema to validate the property for an object. JSON Schema Docs
required defines a list of required properties. JSON Schema docs
requiredOr is used to define when at least one property from a set properties is required.
On the following defined object
{
"properties": {
"a": true,
"b": true,
"c": true
},
"additionalProperties": false
}
The cfn-lint schema
{
"requiredOr": ["a", "b", "c"]
}
is equivalent to the JSON schema
{
"anyOf": [
{
"required": ["a"]
},
{
"required": ["b"]
},
{
"required": ["c"]
}
]
}
requiredXor is used to define when only one property from a set properties is required.
On the following defined object
{
"properties": {
"a": true,
"b": true,
"c": true
},
"additionalProperties": false
}
The cfn-lint schema
{
"requiredXor": ["a", "b", "c"]
}
is equivalent to the JSON schema
{
"oneOf": [
{
"required": ["a"]
},
{
"required": ["b"]
},
{
"required": ["c"]
}
]
}
dependentRequired has been backported into cfn-lint. You can read the definition here
dependentExcluded is the opposite of dependentRequired. The list of properties should not be specified when the key property is specified.
On the following defined object
{
"properties": {
"a": true,
"b": true,
"c": true
},
"additionalProperties": false
}
The cfn-lint schema
{
"dependentExcluded": {
"a": ["b", "c"]
}
}
is equivalent to the JSON schema
{
"dependencies": {
"a": {
"properties": {
"b": false,
"c": false
}
}
}
}