Terraform module for Prowler security scans

As a solution architect one of the pillars for a solution is cost. There are a lot of paid security scanners for your AWS accounts out there but most of them are quite pricey. For start-ups this cost can be prohibitive. Still, you would like to be notified if there are security misconfigurations on your AWS accounts.

Good thing there are great opensource tools that can support us in these situations. However, the surrounding infrastructure can be complex to setup (especially if you have multiple AWS accounts which I always advise for separate workloads).

That is why I made a Terraform module that can be setup in your security account to scan multiple AWS accounts with Prowler and send the findings to Security Hub. The Prowler scans are more detailed compared to the default AWS ones.

This module:

  1. creates a ECS cluster and a VPC.
  2. an Eventbridge rule that periodically starts ECS task, one for each account that needs to be scanned.
  3. An ECS task that sends the output to Security Hub in the scanned account.

When enabling Security Hub, there is a message surrounding AWS Config checks that need to be enabled for it to work properly. If you want to use other scans that AWS offers this might be necessary (you can also leave the standard ones disabled to save costs). Just make sure you understand the cost structure of AWS Config before you enable it. Security Hub on its own is quite cost effective because you just pay for the number of findings that Prowler finds.

AWS Config can get expensive very quickly if you for instance create hundreds of ECS tasks that all need their own ENI adapter in your VPC you will be billed for those configuration changes as well!

Enable Security Hub

In every account you must enable security hub, make sure you are in the right region:

And then go to integrations to find the Prowler integration:

And accept its findings, otherwise they will not appear.

VPC

To save costs the default setup is to use a public subnet in a newly created VPC. You can pass in the option to use a NAT gateway to make sure the tasks do not get a public IP address (of course the data is encrypted in transit). However, this adds a cost of around 35 USD per month (excluding data transfer).

Without a NAT Gateway the task itself will have a public IP but no containers in the task definition listen on any port (and the security group for the task allows no inbound traffic).

You could also use VPC endpoints but then you would need to make an endpoint for every service that Prowler scans and that can be quite cumbersome (and expensive).

If you want to use a NAT gateway set the use_nat_gateway variable to true.

ECS Cluster and task definition

The ECS cluster gets created with container insights disabled to save some costs. We create a single task definition per organization that uses the stable Prowler docker container to run the checks. The task has a role that needs to be created in the account(s) you want to scan.

IAM Role creation

I identify two account IDs in this text:

  1. SCANACCOUNTID: This is the ID of the account being scanned, for example your production or development account ID.
  2. SECURITYACCOUNTID: This is the ID of the account performing the scans. The
  3. SECURITYACCOUNTID and SCANACCOUNTID can be the same if your resources all are in the same account.

The role name is as follows, this role needs to be created in the account(s) you want to scan:

arn:aws:iam::SCANACCOUNTID:role/PREFIXVALUE-scanrole=

The default PREFIXVALUE for the module is prowler-scanner.

This means that in every destination account you want to scan you have to create a IAM role with the name prowler-scanner-scanrole.

This role needs the following trust policy in the accounts you want to scan:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::SECURITYACCOUNTID:role/prowler-scanner-assumerole-SCANACCOUNTID"
    },
    "Action": "sts:AssumeRole"
  }]
}

Remember to replace the SECURITYACCOUNTID and the SCANACCOUNTID above to the account ID that is performing the scans (the security account in our case).

Also, if you changed the prefix value when running the module the prefix will be something different than prowler-scanner.

This trust policy allows the AWS account and role cross account access to the destination account.

This role needs the following permissions policies attached:

The data will be stored in the security hub in the organization where the scan is run. You can enable AWS Organizations to consolidate all details from all accounts in the admin account. For that you must go to Security Hub settings in the admin account and setup a delegated administrator and add the accounts to the Security Hub account (under the tab accounts).

If you do not setup the roles correctly you will have an error like this when the task starts (under logs):

2023-05-30 14:35:52,897 [File: aws_provider.py:100] [Module: aws_provider] CRITICAL: ClientError -- An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::564033685323:assumed-role/prowler-scanner-assumerole-894243019954/523e3995f7e847098737d1521efd120b is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::894243019954:role/prowler-scanner-scanrole

This means that the role in the target account has not been setup correctly (most likely the trust policy is wrong).

If you are having trouble with Prowler sending the data to Security Hub, make sure the role has the permissions to access the Security Hub import (otherwise Prowler will fail silently). You can check CloudTrail for access denies.

Passing a role when starting an ECS task from EventBridge

When you want other services to start an ECS task on your behalf, they need the correct permissions to do so:

  • It needs to be able to run the task with ecs:RunTask
  • It needs to be able to iam:PassRole both the execution role as the task role, it is essential to lock the iam:PassRole call down to prevent privilege escalation!

Here is an example on how to do this with Terraform:

The module handles it for you, but I thought it might be interesting information for people running into the error:

XX is not authorized to perform: iam:PassRole on resource: arn:aws:iam::123456789:role/prowler-scanner-executionrole because no identity-based policy allows the iam:PassRole action”

Remember that you can always debug these things via the CloudTrail console. It shows you exactly what calls are being made to the IAM API’s.

What is next?

You can find the Terraform module here.

You can also use Prowler Pro’s service, but if you are startup, you probably only have money for instant ramen and coffee!