Securing AWS Infrastructure: Prowler and Security Hub Integration with Terraform

There are great open-source tools that can help us in these situations. However, the surrounding infrastructure can be complex to set up, especially if you have multiple AWS accounts, which I always recommend for separate workloads.

I created a Terraform module that can be set up in your security account to scan multiple AWS accounts with Prowler and send the findings to Security Hub.

The Prowler scans provide more detailed results compared to the default AWS scans.

This module:

  1. Creates an ECS cluster and a VPC.

  2. Sets up an EventBridge rule that periodically starts an ECS task for each account that needs to be scanned.

  3. Runs an ECS task that sends the output to Security Hub in the scanned account.

When enabling Security Hub, you'll see a message about 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. However, you can leave the standard ones disabled to save costs. In my case, I disabled the standard ones to save costs.

Security Hub is quite cost-effective because you only pay for the number of findings that Prowler identifies.

AWS Config can become expensive quickly if, for example, you create hundreds of ECS tasks that each require 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 correct region:

Then, go to integrations to find the Prowler integration:

Accept its findings; otherwise, they will not appear.

VPC

To save costs, the default setup uses a public subnet in a newly created VPC. You can choose to use a NAT gateway to ensure the tasks do not get a public IP address (the data is encrypted during transit).

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 does not allow inbound traffic).

You could also use VPC endpoints, but you would need to create an endpoint for every service that Prowler scans, which can be 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 is created with container insights turned off to save costs. We create one task definition per organization using the stable Prowler Docker container to run the checks. The task has a role that must 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, such as your production or development account ID.

  2. SECURITYACCOUNTID: This is the ID of the account performing the scans.

  3. SECURITYACCOUNTID and SCANACCOUNTID can be the same if all your resources are in the same account.

The role name is as follows, and this role needs to be created in the accounts 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 must create an IAM role with the name prowler-scanner-scanrole.

This role requires 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 SECURITYACCOUNTID and SCANACCOUNTID with the account ID that is performing the scans (in our case, the security account).

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

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

This role needs the following permissions policies attached:

The data will be stored in the Security Hub of the organization where the scan is run. You can enable AWS Organizations to gather all details from all accounts into the admin account. To do this, go to the Security Hub settings in the admin account, set up a delegated administrator, and add the accounts to the Security Hub account (under the accounts tab).

If you do not set up the roles correctly, you will see an error like this when the task starts (under logs):

2024-11-29 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 set up correctly, most likely due to an incorrect trust policy.

If you are having trouble with Prowler sending data to Security Hub, ensure the role has the necessary permissions to access the Security Hub import; otherwise, Prowler will fail without any notification.

You can check CloudTrail for access denials.

Passing a role when starting an ECS task from EventBridge

When you want other services to start an ECS task for you, they need the right permissions:

  • They must have permission to run the task with ecs:RunTask.

  • They must have permission to use iam:PassRole for both the execution role and the task role. It's important to restrict the iam:PassRole call to prevent privilege escalation!

GitHub Repository Link

Here is the link to the repository for the modules:
https://github.com/prasant1998/prowler-security-hub-terraform-integration.git