v0.8.0: Variables, Tagging mods & Syntax highlighting →

Custom Controls

Steampipe makes it easy to create your own controls and benchmarks. This allows you to define the controls that are important to you and your organization, and organize them in a way that reflects your organization's standards and practices. (Of course there are controls and benchmarks already available in published Steampipe mods as well if you don't want to write your own).

First, lets create a new workspace for our new benchmark. A workspace is essentially just a filesystem directory from which Steampipe will find and load mod resources.

mkdir untagged
cd untagged

Steampipe will load resources from all .sp files in the workspace. Create a new file in the workspace called untagged.sp and paste in the following code:

control "s3_untagged" {
title = "S3 Untagged"
sql = <<EOT
select
arn as resource,
case
when tags is not null then 'ok'
else 'alarm'
end as status,
case
when tags is not null then name || ' has tags.'
else name || ' has no tags.'
end as reason,
region,
account_id
from
aws_s3_bucket
EOT
}

This snippet defines a control named "s3_untagged", including a sql query to find untagged S3 buckets. Note that the query returns the required control columns (resource, status, and reason), as well as additional columns, or dimensions, to provide context that is specific to AWS (region, account_id).

Now lets run our control:

steampipe check control.s3_untagged

Controls provide an easy to use mechanism for auditing your environment with Steampipe. Benchmarks allow you to group and organize your controls. Lets add another control to the untagged.sp, as well as a benchmark that has both of our controls as children:

control "s3_untagged" {
title = "S3 Untagged"
sql = <<EOT
select
arn as resource,
case
when tags is not null then 'ok'
else 'alarm'
end as status,
case
when tags is not null then name || ' has tags.'
else name || ' has no tags.'
end as reason,
region,
account_id
from
aws_s3_bucket
EOT
}
control "lambda_untagged" {
title = "Lambda Untagged"
sql = <<EOT
select
arn as resource,
case
when tags is not null then 'ok'
else 'alarm'
end as status,
case
when tags is not null then name || ' has tags.'
else name || ' has no tags.'
end as reason,
region,
account_id
from
aws_lambda_function
order by reason
EOT
}
benchmark "untagged" {
title = "Untagged"
children = [
control.lambda_untagged,
control.s3_untagged,
]
}

Now we can run both of our controls via the benchmark:

steampipe check benchmark.untagged

Benchmarks may have also have other benchmarks as children, allowing you to create rich hierarchies of controls.