layout | published | title | order |
---|---|---|---|
default |
true |
Variable Evaluation |
7 |
Checkov supports the evaluation of variables, found in Terraform expressions.
Variables are declared in .tf
files, where each variable has an identifying name,
a description, and an optional default value.
Checkov collects the default values of variables and assigns them to their corresponding references in Terraform expressions.
The advantage of variable evaluation is to cover optional scenarios, in which a forbidden value of a variable, is set inside a Terraform resource configuration. In that scenario, the resource would maybe not meet with certain security compliance.
Recall the CKV_AWS_20
check, which validates if an S3 Bucket has an ACL defined which allows
public access:
class S3PublicACL(BaseResourceCheck):
def __init__(self):
name = "S3 Bucket has an ACL defined which allows public access."
id = "CKV_AWS_20"
supported_resources = ['aws_s3_bucket']
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
def scan_resource_conf(self, conf):
"""
Looks for ACL configuration at aws_s3_bucket:
https://www.terraform.io/docs/providers/aws/r/s3_bucket.html
:param conf: aws_s3_bucket configuration
:return: <CheckResult>
"""
if 'acl' in conf.keys():
acl_block = conf['acl']
if acl_block in [["public-read"],["public-read-write"],["website"]]:
return CheckResult.FAILED
return CheckResult.PASSED
Suppose the following Terraform configuration:
# ./main.tf
resource "aws_s3_bucket" "my_bucket" {
region = var.region
bucket = local.bucket_name
acl = var.acl
force_destroy = true
}
and the following variable file:
# ./variables.tf
variable "bucket_name" {
default = "MyBucket"
}
variable "acl" {
default = "public-read"
}
variable "region" {
default = "us-west-2"
}
### CLI output
Checkov would evaluate var.acl
variable to public-acl
, resulting the check to fail:
> checkov -d .
...
Check: CKV_AWS_20: "S3 Bucket has an ACL defined which allows public access."
FAILED for resource: aws_s3_bucket.my_bucket
File: /main.tf:24-29
24 | resource "aws_s3_bucket" "my_bucket" {
25 | region = var.region
26 | bucket = local.bucket_name
27 | acl = var.acl
28 | force_destroy = true
29 | }
Variable acl (of /variables.tf) evaluated to value "public-acl" in expression: acl = ${var.acl}
Variable region (of /variables.tf) evaluated to value "us-west-2" in expression: region = ${var.region}
To make the check pass, the value of var.acl
needs to be set to private
as follows:
# ./variables.tf
...
variable "acl" {
default = "private"
}
The check result would then pass:
Check: CKV_AWS_20: "S3 Bucket has an ACL defined which allows public access."
PASSED for resource: aws_s3_bucket.template_bucket
File: /main.tf:24-29
Variable acl (of /variables.tf) evaluated to value "public-acl" in expression: acl = ${var.acl}
Variable region (of /variables.tf) evaluated to value "us-west-2" in expression: region = ${var.region}
If available, each PASSED/FAILED
check contains the evaluation information, which contains all the variables
who were evaluated.
Each variable contains it's variable source file path, the evaluated value and the expressions in which it was referenced:
evaluations: {
'<var_name>': {
'var_file': '<variable_file_relative_path>',
'value': '<value>',
'definitions': [
{
'definition_name': 'name',
'definition_expression': '${var.customer_name}_group',
'definition_path': 'resource/0/aws_cognito_user_group/user_group/name/0'
},
{
'definition_name': 'description',
'definition_expression': '${var.customer_name} user group',
'definition_path': 'resource/0/aws_cognito_user_group/user_group/description/0'
}
]
},
...
}
Third party Terraform modules often reduce complexity for deploying services made up of many objects.
For example, the third party EKS module by howdio reduces the terraform required to the nine lines below, however, in doing so abstracts the terraform configuration away from a regular Checkov scan on the current directory.
module "eks" {
source = "howdio/eks/aws"
name = "examplecluster"
default_vpc = true
enable_kubectl = true
enable_dashboard = true
}
To ensure coverage of objects within these modules, you can instruct checkov to scan the .terraform
directory, after a terraform init
, which will have retrieved the third party modules and any associated .tf
files.
terraform init
checkov -d . # Your TF files.
checkov -d .terraform # Module TF files.
It is worth noting however, when scanning the .terraform
directory, Checkov cannot differentiate between third party and internally written modules, however, you will gain scanning coverage for all of them.