This Terraform module helps you assess your multi-account environment in AWS Organizations using Prowler security assessment tool deployed on AWS Fargate. It assesses all accounts using a time-based schedule expression in Amazon CloudWatch, creates assessment reports in CSV format, and stores them in an Amazon Simple Storage Service (S3) bucket.
With AWS Fargate, there are no upfront costs and you pay only for the resources you use. You pay for the amount of vCPU, memory, and storage resources consumed by your containerized Prowler application running on AWS Fargate.
- Programmatically assess the security posture of your accounts in AWS Organizations using Terraform Infrastructure as Code.
- Send Prowler findings to S3 Bucket.
The solution works as follows:
- A time-based CloudWatch Event starts a Fargate task hosting Prowler on a schedule you define.
- Fargate pulls a Prowler Docker image from Amazon Elastic Container Registry (ECR).
- Prowler scans your AWS infrastructure and assumes IAM roles across the accounts.
- Prowler writes the scan results to CSV files in an S3 bucket.
The following prerequisites are required to deploy the solution:
-
A strong understanding of cross account trust relationship policies and IAM policies.
-
Intermediate level knowledge of Terraform.
-
Access to an AWS Organizations privileged user or role that can deploy roles into your organizations sub-accounts.
-
Network Requirements (you will need the Subnet and VPC IDs in your input variables):
-
A VPC with 1 subnet that has access to the Internet; AND
-
A security group that allows outbound access on Port 443 (HTTPS).
-
-
Download and set up Terraform. Refer to the official Terraform instructions to get started.
-
Make sure that your Terraform environment is able to assume an administrative role to implement the resources described in this blog across your member and prowler deployment accounts.
-
Install Git
-
Install latest version of the AWS CLI or use the AWS CloudShell. To use the AWS CLI, you must make sure that you have profiles to assume roles across your accounts. You can get more information about creating CLI configuration files in the AWS CLI user guide.
- Note: The docker image will need to be built and pushed to the ecr outside of CloudShell. There isn't support for running Docker in CloudShell currently.
-
Decide on the appropriate account in which to deploy the Prowler solution (ECS task). AWS recommends deploying the solution in the security account.
-
Get and install Docker where you plan to build the Prowler container image.
- If using a Mac with the new Apple Silicon M processor, you will need to use the experimental docker feature to build the x86 image.
-
Clone the AWS Samples Github repository:
git clone https://github.com/aws-samples/aws-tf-prowler-fargate.git
-
- Creates an Amazon ECR Cluster to run the Prowler container.
- Creates a Prowler task definition for AWS Fargate.
- Enables Amazon CloudWatch Log Group to visualize Prowler execution logs.
- Implements AWS IAM role to trigger container tasks via Amazon EventBridge rule.
- Allows an Amazon EventBridge rule to schedule and invoke the Prowler container using a rate or cron expression.
-
- Defines the Terraform output values of this Terraform module.
-
- Defines the Terraform provider to interact with AWS cloud and/or Terraform state files.
-
- Defines the input variables for this Terraform module.
-
- Refer to the script for line-by-line documentation of each command.
- Loops through all AWS Accounts in AWS Organization, and by default, runs Prowler as follows:
- -R: used to specify Cross-Account role for Prowler to assume to run its assessment.
- -A: used to specify AWS Account number for Prowler to run assessment against.
- -g cislevel2: used to specify cislevel2 checks for Prowler to assess
- -M csv: used to output Prowler reports to CSV files.
-
- Text document that contains all the commands to build Prowler image.
-
- Text document that contains the Prowler run configuration that is pulled by the ECS task once it is provisioned. This tells the Prowler tool what scans to perform and the output format of the report.
Download the Terraform code to an environment configured to access the AWS Organizations Management and member accounts.
```
git clone https://github.com/aws-samples/aws-tf-prowler-fargate
```
Perform the following steps in your Prowler deployment account (for example, Security account):
-
Create an Amazon ECR repository using the AWS CloudShell.
aws ecr create-repository \ --repository-name prowler-repo \ --image-scanning-configuration scanOnPush=true \ --encryption-configuration encryptionType=KMS
-
Make a note of the ECR repository URI. Format: 01234567890.dkr.ecr.us-east-1.amazonaws.com/prowler-repo.
-
To list your ECR repositories use the following command:
aws ecr describe-repositories
The primary prowler configuration for running the scans is contained in prowler-config.txt. You can customize your scan parameters to ensure Prowler is running the appropriate checks for your environment.
Update the variables in prowler-config.txt to configure the checks prowler runs (-g cislevel2) and the report output format (-M csv).
A list of available groups can be found here. Note you cannot run multiple groups simultaneously.
A list of supported output formats (you can select multiple): csv,json,json-asff,html
-
Example 1: Run Prowler checks from the extras group and output the report to CSV.
Edit the following in prowler-config.txt:
PROWLER_SCAN_GROUP=extras PROWLER_OUTPUT_FORMAT=csv
-
Example 2: Run Prowler checks from the cislevel2 group and output the report to CSV, JSON, and HTML.
Edit the following in prowler-config.txt:
PROWLER_SCAN_GROUP=cislevel2 PROWLER_OUTPUT_FORMAT=csv,json,html
-
Obtain ECR login credentials
MacOS or Linux
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 01234567890.dkr.ecr.us-east-1.amazonaws.com
Windows
(Get-ECRLoginCommand).Password | docker login --username AWS --password-stdin 111111111111.dkr.ecr.us-west-2.amazonaws.com
-
Build Prowler Docker Image
MacOS, Linux, Windows
docker build --platform=linux/amd64 --no-cache -t prowler:latest -f Dockerfile .
-
Tag Prowler Docker Image
MacOS, Linux, Windows
docker tag prowler-repo:latest 111111111111.dkr.ecr.us-west-2.amazonaws.com/prowler-repo:latest
-
Push Prowler Docker Image to ECR
MacOS, Linux, Windows
docker push 01234567890.dkr.ecr.us-east-1.amazonaws.com/prowler:latest
To implement Prowler in a designated Prowler deployment account, update the main.tf file in the solution's root directory with your input variables referencing variables.tf (Example 1) or hard code the variables directly into main.tf (Example 2)
-
Example 1: If you use the format below you will need to hard code the variables in variables.tf or you will need to provide them in a myvariables.tfvars file and pass it into the terraform apply command as follows.
terraform apply -var-file [myvariables-example.tfvars](./myvariables-example.tfvars)
module "prowler_ecs_instance_deployment" { source = "./modules/aws-tf-prowler-fargate" providers = { aws = aws.prowler_deployment_account } # The AWS account id for the account that will run Prowler. deployment_accountid = var.deployment_accountid # URI to the repository with the Prowler container image. ecr_image_uri = var.ecr_image_uri # Security Group must allow outbound access on Port 443 (HTTPS). prowler_container_sg_id = var.prowler_container_sg_id # VPC must have internet access. prowler_container_vpc_subnet_id = var.prowler_container_vpc_subnet_id # Optional - Uncomment and specify schedule to override the default schedule (every 7 days) defined in variables.tf. # prowler_schedule_task_expression = var.prowler_schedule_task_expression tags = var.tags }
-
Example 2:
module "prowler_ecs_instance_deployment" { source = "./modules/aws-tf-prowler-fargate" providers = { aws = aws.prowler_deployment_account } # The AWS account id for the account that will run Prowler. deployment_accountid = "123456789011" # URI to the repository with the Prowler container image. ecr_image_uri = "123456789011.dkr.ecr.us-west-2.amazonaws.com/prowler-repo" # Security Group must allow outbound access on Port 443 (HTTPS). prowler_container_sg_id = "sg-1111fea111e1234561" # VPC must have internet access. prowler_container_vpc_subnet_id = "subnet-11b11f1edd1a11e1f" # Optional - Uncomment and specify schedule to override the default schedule (every 7 days) defined in variables.tf. # prowler_schedule_task_expression = var.prowler_schedule_task_expression tags = var.tags }
Modify the main.tf file in the root module using a text editor and update the source variable parameters, deployment account id, ECR image URI (from step 3), VPC security group id and subnet id, and the CloudWatch Event Schedule Expression Rule. The source
argument in a module block tells Terraform where to find the source code for the desired child module. Typical sources include Terraform Registry, local paths, S3 buckets, and many more. See the documentation on Terraform Module Sources for additional information.
-
Now that you have updated the script with your variable configuration, you can initialize the directory. Initializing a configuration directory downloads and installs the AWS provider, which is defined in the configuration:
terraform init
You should see a message that says
Terraform has been successfully initialized!
and the version of the provider that was installed. -
You should format and validate your configuration. The
terraform fmt
command automatically updates configurations in the current directory for readability and consistency. You can also make sure that your configuration is syntactically valid and consistent using theterraform validate
command:terraform fmt terraform validate
-
Apply the configuration to create the infrastructure:
terraform apply
OR
If you are passing in a local variables file you can pass them to terraform apply as follows:
terraform apply -var-file myvariables-example.tfvars
-
Before applying any configuration changes, Terraform prints out the execution plan to describe the actions that Terraform will take to update your infrastructure. Once prompted, you will need to type
yes
to confirm that the plan can be run. -
Take note of the S3 Prowler Bucket name once it’s created. You will need the bucket name when deploying the cross-account role in the following steps.
Do NOT deploy this role into the prowler deployment account (the account that will be hosting your prowler instance, e.g. security account). The main Prowler module that deploys the ECS instance and task also creates a slightly modified version of the prowler role in the deployment account.
-
Deploy the aws-tf-iam-role module to your AWS Organizations Management account.
If you don't deploy the Prowler cross account role into your management account you will see permissions errors in the Prowler task logs when you attempt to run the ECS task.
-
Deploy the aws-tf-iam-role module to your AWS Organizations member accounts to be assessed by Prowler.
-
You will need to comment out the aws-tf-prowler-fargate module block from main.tf.
## Call Module to Deploy the Prowler ECS Instance and Role # module "prowler_ecs_instance_deployment" { # source = "./modules/aws-tf-prowler-fargate" # providers = { # aws = aws.prowler_deployment_account # } # # The AWS account id for the account that will run Prowler. # deployment_accountid = var.deployment_accountid # # URI to the repository with the Prowler container image. # ecr_image_uri = var.ecr_image_uri # # Security Group must allow outbound access on Port 443 (HTTPS). # prowler_container_sg_id = var.prowler_container_sg_id # # VPC must have internet access. # prowler_container_vpc_subnet_id = var.prowler_container_vpc_subnet_id # # Optional - Uncomment and specify schedule to override the default schedule (every 7 days) defined in variables.tf. # # prowler_schedule_task_expression = var.prowler_schedule_task_expression # tags = var.tags # }
-
Update the aws-tf-iam-role module block for prowler_iam_cross_account_role_# in main.tf in the root directory. The code should look similar to the examples below:
Example:
The prowler_s3 bucket should be the name of the bucket that was deployed by the aws-tf-prowler-fargate module.
module "prowler_iam_cross_account_management_account" { source = "./modules/aws-tf-iam-role" providers = { aws = aws.prowler_scan_management_account } # The AWS account id for the account that will run Prowler. deployment_accountid = var.deployment_accountid prowler_s3 = "prowler-111111111111-us-west-2" } module "prowler_iam_cross_account_role_1" { source = "./modules/aws-tf-iam-role" providers = { aws = aws.prowler_account_scan_account_1 } # The AWS account id for the account that will run Prowler. deployment_accountid = 1111111111 prowler_s3 = "prowler-1111111111-us-west-2" }
-
Update the providers.tf file to deploy to multiple accounts.
Specific guidance on multi-account deployment is not in scope for this article since this can be accomplished through several methods depending on your particular environment, configuration, and personal preference. Please see the official Terraform documentation on multi-account deployments with Terraform. The examples below are provided as a reference point.
Example of providers.tf configuration to deploy to multiple accounts.
# Prowler Scan Management Account provider "aws" { region = var.region_primary alias = "prowler_scan_management_account" } # Prowler Scan Account 1 provider "aws" { region = var.region_primary alias = "prowler_account_scan_account_1" assume_role { role_arn = "arn:aws:iam::123456789012:role/ROLE_NAME" session_name = "deploy_prowler_role" #external_id = "EXTERNAL_ID" } } # Prowler Scan Account 2 provider "aws" { region = var.region_primary alias = "prowler_account_scan_account_2" assume_role { role_arn = "arn:aws:iam::123456789012:role/ROLE_NAME" session_name = "deploy_prowler_role" #external_id = "EXTERNAL_ID" } }
-
Alternatively, this role can be deployed with CloudFormation StackSets. The CloudFormation template file is available here.
By default, the Prowler task is configured to run every 7 days using the CloudWatch Event Rule. You can trigger a manual run of the task using the following command. Ensure you replace the value of the subnet-0111111111111111111
with your subnet id. In addition, the task requires Internet connection to download the Prowler source code.
aws ecs run-task --launch-type FARGATE \
--task-definition prowler-security-assessment \
--cluster prowler-security-assessment-cluster \
--network-configuration "awsvpcConfiguration={subnets=[subnet-0111111111111111111],assignPublicIp=ENABLED}"
You have successfully implemented the Prowler security assessment tool on AWS Fargate using Terrraform. You should see see logs from the container tasks in your ECS task definition.
Utilize CloudWatch Insights to find the current status of your Prowler scan.
-
Login to the AWS Console and navigate the CloudWatch.
-
From the CloudWatch main page navigate to Logs then Logs Insights in the lefthand menu.
-
On the Logs Insights page select the Prowler log group from the dropdown menu.
-
Select the appropriate timeframe for your search.
-
Enter one of the queries below.
- Find Scan Start Time
fields @message | parse @message “Assessing AWS Account: *, *” as @account_id, @starttime | filter ispresent(@account_id)| sort @account_id desc | display @account_id, @timestamp, @starttime
- Find Scan End Time
fields @message | parse @message “Completed AWS Account: * in *” as @account_id, @endtime | filter ispresent(@account_id) | sort @account_id desc | display @account_id, @timestamp, @endtime
- Regex to Extract Scan Start and End Times
fields @message | parse @message /Assessing AWS Account: (?<account_id_start>[0-9]{12}), using Role: prowler-sec-assessment-role on (?<start_time>.*)|Completed AWS Account: (?<account_id_completed>[0-9]{12}) in (?<end_time>.+)/ | sort @account_id_start asc
Prowler supports native integration to send findings to AWS Security Hub. This integration allows Prowler to import its findings to AWS Security Hub for a comprehensive view which aggregates, organizes, and prioritizes your security alerts or findings. Refer to the Security Hub Integration for further information.
All provider requirements can be found in providers.tf.
Name | Type |
---|---|
aws_iam_role | Resource |
aws_iam_role_policy | Resource |
aws_iam_role_policy_attachment | Resource |
aws_s3_bucket | Resource |
aws_s3_bucket_versioning | Resource |
aws_s3_bucket_acl | Resource |
aws_s3_bucket_server_side_encryption_configuration | Resource |
aws_s3_bucket_public_access_block | Resource |
aws_s3_bucket_policy | Resource |
aws_ecs_cluster | Resource |
aws_ecs_task_definition | Resource |
aws_cloudwatch_log_group | Resource |
aws_cloudwatch_event_rule | Resource |
aws_cloudwatch_event_target | Resource |
All variable details can be found in tf-prowler-aws-fargate/variables.tf. Refer to the file for default variable values.
Variable Name | Description | Required |
---|---|---|
bucket |
The name of the bucket. | Yes |
inbound_tags |
Tag map to be applied to all taggable resources created by this module. | Yes |
kms_master_key_id |
The AWS KMS master key ID used for SSE-KMS encryption. | Yes |
ecs_cluster_name |
AWS Fargate Cluser Name. | Yes |
ecs_task_definition_name |
Unique ECS Task Definition Name. | Yes |
ecs_task_execution_arn |
Name of the IAM role that allows Fargate to publish logs to CloudWatch and to download Prowler image from Amazon ECR | No |
ecs_task_role_name |
Name of the IAM role with the permissions that Prowler needs to complete its scans. | Yes |
ecs_task_role_arn |
Arn of the IAM role with the permissions that Prowler needs to complete its scans. | Yes |
fargate_task_cpu |
CPU Reservation for AWS Fargate Task. | Yes |
fargate_memory |
Memory Reservation for AWS Fargate Task. | Yes |
ecr_image_uri |
URI Path of the Prowler Docker Image - Preferably from ECR. | Yes |
container_name |
Name of the Container within AWS Fargate. | Yes |
cwe_log_prefix |
Prefix for CloudWatch Event Log Group. | Yes |
reporting_bucket |
Name of the S3 bucket to store Prowler reports. | Yes |
reporting_bucket_account_id |
Account ID of the S3 bucket to store prowler reports. | Yes |
prowler_schedule_task_expression |
Schedule Expression to run the Prowler AWS Fargate Task. | Yes |
prowler_scheduled_task_event_role |
Name of the IAM Role for the CloudWatch Event Task Scheduler for AWS Fargate. | Yes |
fargate_platform_version |
FARGATE Platform Version. | Yes |
prowler_container_sg_id |
Prowler container Security Group ID. | Yes |
prowler_container_vpc_subnet_id |
Prowler container Subnet ID. | Yes |
log_retention_in_days |
Number of days container task logs will be retained in CloudWatch. | Yes |
assign_container_public_ip |
Assign public IP to the container. | Yes |
tags |
A map of tags (key-value pairs) passed to resources. | Yes |
All output details can be found in outputs.tf.
Output Name | Description |
---|---|
ecs_cluster_arn |
ARN of the AWS Fargate Cluster |
ecs_task_definition |
ARN of the ECS Task Definition |
s3_bucket |
ARN of the S3 Bucket |
iam_role |
ARN of the Prowler role |
cloudwatch_log_group |
ARN of the Amazon CloudWatch Log Group |
A complete Changelog history can be found in CHANGELOG.md.
See CONTRIBUTING for more information.
This library is licensed under the MIT-0 License. See the LICENSE file.