Automating Prowler for Compliance Checking in AWS
Tags: cloud, aws, security, cloudformation
Published: 2022-03-27 18:15:23

Whether you are looking to improve your AWS security posture or checking compliance against cybersecurity frameworks, [Prowler](https://github.com/prowler-cloud/prowler) is an amazing open source tool developed by [Toni de la Fuente](https://blyx.com/). Toni has created a tool to check over 200 security controls in AWS ranging from ensuring S3 buckers are not publicly accessible to encryption everywhere. 

Toni's Github portal provides extensive documentation on how to use the tool, but I wanted to share a CloudFormation template that I created to automate the deployment in AWS to run compliance checks and then decommission the stack and remove all resources.

## Launching EC2 Instance for Prowler

First, we will want launch an EC2 instance and run a bash script to download the necessary software, install, and configure Prowler.

```yaml
  ProwlerInstance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      SubnetId: !Ref SubnetId
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      KeyName: !Ref KeyName
      IamInstanceProfile: !Ref ProwlerInstanceProfile
      Tags:
        -
          Key: Name
          Value: Prowler
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
            Encrypted: true
# Run bash to install and configure Prowler
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            sudo yum update -y
            sudo yum remove -y awscli
            cd /home/ec2-user
            curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/home/ec2-user/awscliv2.zip"
            unzip /home/ec2-user/awscliv2.zip
            sudo /home/ec2-user/aws/install
            sudo yum install -y python3 jq git
            sudo pip3 install detect-secrets==1.0.3
            git clone https://github.com/prowler-cloud/prowler /home/ec2-user/prowler
            chown -R ec2-user:ec2-user /home/ec2-user/prowler
```

## Create an instance profile

Create an instance profile tied to a role with necessary permissions to run the audit.

```yaml
  ProwlerInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: prowler-ec2-instance-profile
      Path: /
      Roles:
       - !Ref ProwlerEc2InstanceRole
```

## Provide access to run Prowler

Next we will want to generate a role that has view-only and security audit permission that is required by Prowler to run compliance checks.

```yaml
  ProwlerEc2InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: prowler-ec2-instance-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/SecurityAudit
        - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
      Path: /
```

## Security Group

We'll want to create a security group to only allow SSH access into the EC2 instance.

```yaml
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: Allow ssh from specific host
        GroupName: ProwlerSecurityGroup
        VpcId: !Ref VpcId
        SecurityGroupIngress:
          - IpProtocol: 'tcp'
            FromPort: '22'
            ToPort: '22'
            CidrIp: !Ref CidrIp
```

## Parameters

Lastly, to improve automation, we will pass parameters into the CloudFormation template. If you launch the template via the console, some of these settings will be selected via a dropdown. For launching via the command-line interface, pass the parameters through a JSON file.

ImageId : Default is AWS Linux 2 **ami-0e1d30f2c40c4c701**  
InstanceType : Default is **t3.micro**  
VpcId : VPC to launch EC2 instance into  
SubnetId : Subnet for EC2 instance  
KeyName : Keypair to use  
CidrIp : CIDR range for SSH x.x.x.x/x

```yaml
Parameters:
  ImageId:
    Type: String
    Description: AMI - Linux 2
    Default: 'ami-0e1d30f2c40c4c701'
  InstanceType:
    Type: String
    Description: Instance type to be used - t3.micro default
    Default: t3.micro
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC to be used
  SubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: Subnet to be used
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Keyname
  CidrIp:
    Type: String
    Description: CidrIp to be used to connect from x.x.x.x/x
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Label:
          default: "Network Configuration"
        Parameters:
          - ImageId
          - InstanceType
          - VpcId
          - SubnetId
          - KeyName
          - CidrIp
```

## Final YAML Script

After putting all this together. The final YAML scripts looks like the following. The code is also available at [Github](https://github.com/jamesmonek/prowler-cloudformation).

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Create EC2 instanace with Prowler pre-configured and tied to roles to run"
# Template Parameters
# ImageId : Default is AWS Linux 2 ami-0e1d30f2c40c4c701
# InstanceType : Default is t3.micro
# VpcId : VPC to launch in
# SubnetId : Subnet to connect
# KeyName : Keypair to use
# CidrIp : CIDR range for SSH x.x.x.x/x
Resources:
# Create Prowler Instance - Parameters for ImageId, InstanceType, SubnetId, SecurityGroupIds, and KeyName
  ProwlerInstance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      SubnetId: !Ref SubnetId
      SecurityGroupIds:
        - !Ref InstanceSecurityGroup
      KeyName: !Ref KeyName
      IamInstanceProfile: !Ref ProwlerInstanceProfile
      Tags:
        -
          Key: Name
          Value: Prowler
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
            Encrypted: true
# Run bash to install and configure Prowler
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            sudo yum update -y
            sudo yum remove -y awscli
            cd /home/ec2-user
            curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "/home/ec2-user/awscliv2.zip"
            unzip /home/ec2-user/awscliv2.zip
            sudo /home/ec2-user/aws/install
            sudo yum install -y python3 jq git
            sudo pip3 install detect-secrets==1.0.3
            git clone https://github.com/prowler-cloud/prowler /home/ec2-user/prowler
            chown -R ec2-user:ec2-user /home/ec2-user/prowler
  ProwlerInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: prowler-ec2-instance-profile
      Path: /
      Roles:
       - !Ref ProwlerEc2InstanceRole
# Create Security Group
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: Allow ssh from specific host
        GroupName: ProwlerSecurityGroup
        VpcId: !Ref VpcId
        SecurityGroupIngress:
          - IpProtocol: 'tcp'
            FromPort: '22'
            ToPort: '22'
            CidrIp: !Ref CidrIp
# Create EC2 Instance Role to run security checks and attach to instance
  ProwlerEc2InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: prowler-ec2-instance-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/SecurityAudit
        - arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
      Path: /
# Parameters for cloudformation template with some defaults
Parameters:
  ImageId:
    Type: String
    Description: AMI - Linux 2
    Default: 'ami-0e1d30f2c40c4c701'
  InstanceType:
    Type: String
    Description: Instance type to be used - t3.micro default
    Default: t3.micro
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: VPC to be used
  SubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: Subnet to be used
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Keyname
  CidrIp:
    Type: String
    Description: CidrIp to be used to connect from x.x.x.x/x
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Label:
          default: "Network Configuration"
        Parameters:
          - ImageId
          - InstanceType
          - VpcId
          - SubnetId
          - KeyName
          - CidrIp
Conditions: {}
```

## Running Prowler

After launching the CloudFormation template, simply sign into the EC2 instance and change into the /home/ec2-user/prowler directory.

To start, I recommend running Prowler with the HTML output file option. This provides a dynamic HTML file that you can review all the findings.

```bash
./prowler -M html
```

You can run direct output to multiple formats at once such as csv and json

```bash
./prowler -M csv,json,html
```

## Decommissioning the resources

After you run Prowler, copy the output files to another system or S3 for review and record keeping. Go back into CloudFormation and delete the stack to remove all the resources that were generated.

## Next steps

Prowler is also supported by AWS Security Hub, so you can send your findings directly to Security Hub. There's also a workshop available to build security dashboards in Quicksight from Prowler data. Details for this integration can be found at [Building Prowler into a QuickSight powered AWS Security Dashboard](https://catalog.us-east-1.prod.workshops.aws/workshops/b1cdc52b-eb11-44ed-8dc8-9dfe5fb254f5/en-US).