Prowler on AWS

Prowler on AWS

Prowler is an awesome open source tool for auditing AWS settings within an account or many accounts across an organisation.

https://github.com/toniblyx/prowler

The docs in the project are awesome but as a summary it does all this cool stuff.

  • get a direct colorful or monochrome report
  • a HTML, CSV, JUNIT, JSON or JSON ASFF format report
  • send findings directly to Security Hub
  • run specific checks and groups or create your own
  • check multiple AWS accounts in parallel or sequentially
  • and more!

Junit

AWS announced support for JUnit reporting as part of a CodeBuild Project some time ago.

https://aws.amazon.com/blogs/devops/test-reports-with-aws-codebuild

I thought it would be great to integrate this with the outputs from prowler to provide full account audits nicely packaged up into a single Cloudformation template.

Workflow

The following workflow is implemented within the CloudFormation template.

Workflow

  • CodeBuild project kicks off a container
  • Container installs a few dependancies like AWS Cli, detect-secrets and clones the prowler repo from GitHub
  • Kick off a prowler run to audit the settings within the account
  • prowler outputs the JUnit files and CodeBuild posts them to a report group

Each run will create a summary report as follows and you can filter based on success, fail and see the outputs for each of the tests executed.

Report Group

Cloudformation Template

Once you provision this template to the target account you will be provided with a CodeBuild project that can be run adhoc to audit all the setting within the account.

Codebuild

Should you want to adjust the prowler command edit line 155 with your desired parameters. I'm targeting on ap-southeast-2 for example in the default prowler command as follows

./prowler -r ap-southeast-2 -f ap-southeast-2 -M junit-xml
---
AWSTemplateFormatVersion: 2010-09-09
Description: Creates a CodeBuild project to audit the AWS account with prowler https://github.com/toniblyx/prowler

Parameters:
  ServiceName:
    Description: 'Specifies the service name used within component naming'
    Type: String
    Default: 'prowler'

  LogsRetentionInDays:
    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'
    Type: Number
    Default: 3
    AllowedValues: [1, 3, 5, 7, 14, 30, 60]

Resources:
  ArtifactBucket:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: Name
          Value: !Join ['-', ['AP2', 'INF', !Ref 'ServiceName', !Ref 'AWS::AccountId', 'S3', 'Prowler']]
      BucketName: !Sub '${ServiceName}-${AWS::Region}-prowler-${AWS::AccountId}'
      AccessControl: LogDeliveryWrite
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref 'ArtifactBucket'
      PolicyDocument:
        Id: Content
        Version: '2012-10-17'
        Statement:
          - Action: '*'
            Condition:
              Bool:
                aws:SecureTransport: 'false'
            Effect: Deny
            Principal: '*'
            Resource:
              - !Join ['', ['arn:aws:s3:::', !Ref 'ArtifactBucket', '/*']]
            Sid: S3ForceSSL
          - Action: 's3:PutObject'
            Condition:
              'Null':
                s3:x-amz-server-side-encryption: 'true'
            Effect: Deny
            Principal: '*'
            Resource:
              - !Join ['', ['arn:aws:s3:::', !Ref 'ArtifactBucket', '/*']]
            Sid: DenyUnEncryptedObjectUploads

  # Codebuild Projects
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "Explicit name is required for this resource to avoid circular dependencies."
    Properties:
      RoleName: prowler-codebuild-role
      Path: '/service-role/'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/job-function/SupportUser'
        - 'arn:aws:iam::aws:policy/job-function/ViewOnlyAccess'
        - 'arn:aws:iam::aws:policy/SecurityAudit'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          -
            Action: 'sts:AssumeRole'
            Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
      Policies:
        - PolicyName: LogGroup
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Effect: Allow
                Resource: !Sub 'arn:aws:logs:ap-southeast-2:${AWS::AccountId}:log-group:/aws/codebuild/*'
        - PolicyName: S3
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
                Effect: Allow
                Resource: !Sub 'arn:aws:s3:::${ArtifactBucket}/*'
        - PolicyName: CodeBuild
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - codebuild:CreateReportGroup
                  - codebuild:CreateReport
                  - codebuild:UpdateReport
                  - codebuild:BatchPutTestCases
                  - codebuild:BatchPutCodeCoverages
                Effect: Allow
                Resource: !Sub 'arn:aws:codebuild:ap-southeast-2:${AWS::AccountId}:report-group/*'
        - PolicyName: AssumeRole
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - sts:AssumeRole
                Effect: Allow
                Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/prowler-codebuild-role'

  ProwlerCodeBuild:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: NO_ARTIFACTS
      Source:
        Type: NO_SOURCE
        BuildSpec: |
          version: 0.2
          phases:
            install:
              runtime-versions:
                python: 3.8
              commands:
                - pip3 install detect-secrets
                - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
                - unzip awscliv2.zip
                - ./aws/install
                - git clone https://github.com/toniblyx/prowler
            build:
              commands:
                - cd prowler
                - ./prowler -r ap-southeast-2 -f ap-southeast-2 -M junit-xml
          reports:
            prowler:
              files:
                - '**/*'
              base-directory: 'prowler/junit-reports'
              file-format: JunitXml
      Environment:
        ComputeType: "BUILD_GENERAL1_SMALL"
        Image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
        Type: "LINUX_CONTAINER"
      Description: Run Prowler audit for the SMC
      ServiceRole: !GetAtt CodeBuildServiceRole.Arn
      TimeoutInMinutes: 300

  ProwlerCodeBuildReportGroup:
    Type: AWS::CodeBuild::ReportGroup
    Properties:
      Name: prowler
      Type: TEST
      ExportConfig:
        ExportConfigType: NO_EXPORT

  ProwlerLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: !Sub '/aws/codebuild/${ProwlerCodeBuild}'
      RetentionInDays: !Ref LogsRetentionInDays

Outputs:
  ArtifactBucketName:
    Description: Artifact Bucket Name
    Value: !Ref 'ArtifactBucket'
    Export:
      Name: !Sub 'ArtifactBucketName-${ServiceName}'

Opensource

There were a couple of changes that needed to be made to the JUnit output for this to work within CodeBuild initially. Additional metadata was required within the JUnit test output summaries so I raised my first issue against an OpenSource project.

https://github.com/toniblyx/prowler/issues/673

I then followed it up with a proposed change which as noted was a little gnarly :)

https://github.com/toniblyx/prowler/pull/671

The maintainers were great, and friendly and walked me through getting my first PR merged! Big thanks to you both!

I hope this experience encourages others to contribute to OpenSource projects like Prowler in the future.

Thanks for reading!

Cheers

For more articles on Prowler click here!

Did you find this article valuable?

Support Stephen Jones by becoming a sponsor. Any amount is appreciated!