├── Architecture.jpg ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── ProwlerToSecurityHub_CloudFormation.yml └── README.md /Architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-security-hub-prowler-integrations/ec37e24d8ef69ff96d236411a94ffdcae52c9dfc/Architecture.jpg -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | # software and associated documentation files (the "Software"), to deal in the Software 6 | # without restriction, including without limitation the rights to use, copy, modify, 7 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | # permit persons to whom the Software is furnished to do so. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 12 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 13 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 14 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 15 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | FROM python:latest 18 | 19 | # Declar Env Vars 20 | ENV MY_DYANMODB_TABLE=MY_DYANMODB_TABLE 21 | ENV AWS_REGION=AWS_REGION 22 | 23 | # Install Dependencies 24 | RUN \ 25 | apt update && \ 26 | apt upgrade -y && \ 27 | pip install awscli && \ 28 | pip install detect-secrets && \ 29 | apt install jq -y && \ 30 | apt install -y python3-pip 31 | 32 | # Place scripts 33 | ADD converter.py /root 34 | ADD loader.py /root 35 | ADD script.sh /root 36 | 37 | # Installs prowler, moves scripts into prowler directory 38 | RUN \ 39 | git clone https://github.com/toniblyx/prowler && \ 40 | mv root/converter.py /prowler && \ 41 | mv root/loader.py /prowler && \ 42 | mv root/script.sh /prowler 43 | 44 | # Runs prowler, ETLs ouput with converter and loads DynamoDB with loader 45 | WORKDIR /prowler 46 | RUN pip3 install boto3 47 | CMD bash script.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /ProwlerToSecurityHub_CloudFormation.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: This Template will create the supporting infrastructure for the Prowler Fargate AWS Security Blog Post 3 | Parameters: 4 | ProwlerClusterName: 5 | Type: String 6 | Description: Name of the ECS Cluster that the Prowler Fargate Task will run in 7 | Default: ProwlerCluster 8 | ProwlerContainerName: 9 | Type: String 10 | Description: Name of the Prowler Container Definition within the ECS Task 11 | Default: prowler 12 | ProwlerContainerInfo: 13 | Type: String 14 | Description: ECR URI of the Prowler container 15 | ProwlerExecutionRole: 16 | Type: String 17 | Description: ARN of the IAM Task Execution Role ECS uses to pull images from ECR and send logs to CloudWatch 18 | ProwlerTaskRole: 19 | Type: String 20 | Description: ARN of the Task IAM Role that gives Prowler permissions to perform its checks 21 | ProwlerSecurityGroup: 22 | Type: String 23 | Description: Security Group that allows at least HTTPS 443 inbound/outbound 24 | ProwlerScheduledSubnet1: 25 | Type: String 26 | Description: Subnet Id in which Prowler can be scheduled to Run 27 | ProwlerScheduledSubnet2: 28 | Type: String 29 | Description: A secondary Subnet Id in which Prowler can be scheduled to Run 30 | Resources: 31 | ProwlerReportDynamoDBTable: 32 | Type: AWS::DynamoDB::Table 33 | Properties: 34 | AttributeDefinitions: 35 | - 36 | AttributeName: "NOTES" 37 | AttributeType: "S" 38 | KeySchema: 39 | - 40 | AttributeName: "NOTES" 41 | KeyType: "HASH" 42 | ProvisionedThroughput: 43 | ReadCapacityUnits: "50" 44 | WriteCapacityUnits: "50" 45 | TableName: !Sub 'prowler-report-table-${AWS::AccountId}' 46 | StreamSpecification: 47 | StreamViewType: NEW_IMAGE 48 | ProwlerECSCloudWatchLogsGroup: 49 | Type: AWS::Logs::LogGroup 50 | Properties: 51 | LogGroupName: !Join [ "-", [ !Ref ProwlerContainerName, !Ref 'AWS::StackName' ] ] 52 | RetentionInDays: 90 53 | ProwlerECSCluster: 54 | Type: AWS::ECS::Cluster 55 | Properties: 56 | ClusterName: !Ref ProwlerClusterName 57 | ProwlerECSTaskDefinition: 58 | Type: AWS::ECS::TaskDefinition 59 | Properties: 60 | ContainerDefinitions: 61 | - 62 | Image: !Ref ProwlerContainerInfo 63 | Name: !Ref ProwlerContainerName 64 | Environment: 65 | - Name: MY_DYANMODB_TABLE 66 | Value: !Ref ProwlerReportDynamoDBTable 67 | LogConfiguration: 68 | LogDriver: awslogs 69 | Options: 70 | awslogs-group: !Ref ProwlerECSCloudWatchLogsGroup 71 | awslogs-region: !Ref 'AWS::Region' 72 | awslogs-stream-prefix: ecs 73 | Cpu: 2048 74 | ExecutionRoleArn: !Ref ProwlerExecutionRole 75 | Memory: 4096 76 | NetworkMode: awsvpc 77 | TaskRoleArn: !Ref ProwlerTaskRole 78 | Family: Prowler2SecurityHubTask 79 | RequiresCompatibilities: 80 | - FARGATE 81 | ProwlerTaskScheduler: 82 | Type: AWS::Events::Rule 83 | Properties: 84 | ScheduleExpression: "rate(7 days)" 85 | State: ENABLED 86 | Targets: 87 | - Arn: !GetAtt ProwlerECSCluster.Arn 88 | RoleArn: !Ref ProwlerTaskRole 89 | Id: prowlerTaskScheduler 90 | EcsParameters: 91 | TaskDefinitionArn: !Ref ProwlerECSTaskDefinition 92 | TaskCount: 1 93 | LaunchType: FARGATE 94 | PlatformVersion: 'LATEST' 95 | NetworkConfiguration: 96 | AwsVpcConfiguration: 97 | AssignPublicIp: ENABLED 98 | SecurityGroups: 99 | - !Ref ProwlerSecurityGroup 100 | Subnets: 101 | - !Ref ProwlerScheduledSubnet1 102 | - !Ref ProwlerScheduledSubnet2 103 | DynamoStreamLambdaMapping: 104 | Type: AWS::Lambda::EventSourceMapping 105 | Properties: 106 | BatchSize: 1 107 | Enabled: True 108 | EventSourceArn: 109 | Fn::GetAtt: [ ProwlerReportDynamoDBTable , StreamArn ] 110 | FunctionName: 111 | Fn::GetAtt: [ ProwlertoSecHubLambdaFunction , Arn ] 112 | StartingPosition: LATEST #always start at the tail of the stream 113 | ProwlertoSecHubLambdaFunction: 114 | Type: AWS::Lambda::Function 115 | Properties: 116 | FunctionName: Prowler2SecurityHub 117 | Description: Maps Prowler findings sent from ECS to DynamoDB into the ASFF via DynamoDB Streams before importing to Security Hub 118 | Handler: index.lambda_handler 119 | MemorySize: 384 120 | Role: !GetAtt ProwlertoSecHubLambdaRole.Arn 121 | Runtime: python3.7 122 | Timeout: 70 123 | Environment: 124 | Variables: 125 | account_num: !Ref 'AWS::AccountId' 126 | region: !Ref 'AWS::Region' 127 | Code: 128 | ZipFile: | 129 | import json 130 | import boto3 131 | import datetime 132 | import uuid 133 | import os 134 | def lambda_handler(event, context): 135 | # import Lambda ENV VARs 136 | accountId = os.environ['account_num'] 137 | awsRegion = os.environ['region'] 138 | # Use Prowler finding notes for ASFF Description 139 | prowlerDescription = str(event['Records'][0]['dynamodb']['NewImage']['NOTES']['S']) 140 | # Use Prowler finding title text for ASFF Title 141 | prowlerTitle = str(event['Records'][0]['dynamodb']['NewImage']['TITLE_TEXT']['S']) 142 | # looping through Prowler score result, set severity & compliance based on finding 143 | prowlerResult = str(event['Records'][0]['dynamodb']['NewImage']['RESULT']['S']) 144 | if prowlerResult == 'PASS': 145 | prowlerComplianceRating = 'PASSED' 146 | prowlerProductSev = int(0) 147 | prowlerProductNorm = int(0) 148 | elif prowlerResult == 'INFO': 149 | prowlerComplianceRating = 'NOT_AVAILABLE' 150 | prowlerProductSev = int(1) 151 | prowlerProductNorm = int(1) 152 | elif prowlerResult == 'FAIL': 153 | prowlerComplianceRating = 'FAILED' 154 | prowlerProductSev = int(8) 155 | prowlerProductNorm = int(80) 156 | else: 157 | print("No Compliance Info Found!") 158 | # ISO Time 159 | iso8061Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() 160 | # ASFF BIF Id 161 | asffID = str(uuid.uuid4()) 162 | # import security hub boto3 client 163 | sechub = boto3.client('securityhub') 164 | # call BIF 165 | try: 166 | response = sechub.batch_import_findings( 167 | Findings=[ 168 | { 169 | 'SchemaVersion': '2018-10-08', 170 | 'Id': asffID, 171 | 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + accountId + ':product/' + accountId + '/default', 172 | 'ProductFields': { 173 | 'ProviderName': 'Prowler', 174 | 'ProviderVersion': 'v2.1.0', 175 | }, 176 | 'GeneratorId': asffID, 177 | 'AwsAccountId': accountId, 178 | 'Types': [ 'Software and Configuration Checks' ], 179 | 'FirstObservedAt': iso8061Time, 180 | 'UpdatedAt': iso8061Time, 181 | 'CreatedAt': iso8061Time, 182 | 'Severity': { 183 | 'Product': prowlerProductSev, 184 | 'Normalized': prowlerProductNorm 185 | }, 186 | 'Title': prowlerTitle, 187 | 'Description': prowlerDescription, 188 | 'Resources': [ 189 | { 190 | 'Type': 'AwsAccount', 191 | 'Id': 'AWS::::Account:' + accountId, 192 | 'Partition': 'aws', 193 | 'Region': awsRegion, 194 | } 195 | ], 196 | 'WorkflowState': 'NEW', 197 | 'Compliance': {'Status': prowlerComplianceRating}, 198 | 'RecordState': 'ACTIVE' 199 | } 200 | ] 201 | ) 202 | print(response) 203 | except Exception as e: 204 | print(e) 205 | print("Submitting finding to Security Hub failed, please troubleshoot further") 206 | raise 207 | ProwlertoSecHubLambdaRole: 208 | Type: AWS::IAM::Role 209 | Properties: 210 | Policies: 211 | - PolicyName: Prowler2SecurityHub-Policy 212 | PolicyDocument: 213 | Version: 2012-10-17 214 | Statement: 215 | - Effect: Allow 216 | Action: 217 | - cloudwatch:PutMetricData 218 | - securityhub:BatchImportFindings 219 | Resource: '*' 220 | - Effect: Allow 221 | Action: 222 | - logs:CreateLogGroup 223 | - logs:CreateLogStream 224 | - logs:PutLogEvents 225 | Resource: '*' 226 | - Effect: Allow 227 | Action: 228 | - dynamodb:GetRecords 229 | - dynamodb:GetShardIterator 230 | - dynamodb:DescribeStream 231 | - dynamodb:ListStreams 232 | Resource: !GetAtt ProwlerReportDynamoDBTable.StreamArn 233 | AssumeRolePolicyDocument: 234 | Version: 2012-10-17 235 | Statement: 236 | - Effect: Allow 237 | Principal: { Service: lambda.amazonaws.com } 238 | Action: 239 | - sts:AssumeRole 240 | Outputs: 241 | ProwlerReportDynamoDBTable: 242 | Description: DynamoDB Table to upload ETLed Prowler findings 243 | Value: !Ref ProwlerReportDynamoDBTable -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Use AWS Fargate and Prowler to send AWS Service security configuration findings to Security Hub 2 | The code in this repo accompanies the AWS Security Blog Post: Use AWS Fargate and Prowler to send AWS Service security configuration findings to Security Hub. Prowler checks are ran from a container running on AWS Fargate which are sent to DynamoDB for persistence. Subsequent checks won't be sent to Security Hub if they are duplicate findings as only New Images are sent to the Stream. 3 | 4 | For more information on Prowler see: https://github.com/toniblyx/prowler 5 | For more information on DynamoDB Streams see: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html 6 | 7 | ### Getting Started 8 | Copy or download the AWS CloudFormation template `ProwlerToSecurityHub_CloudFormation.yml` and create a Stack from it. The rest of the instructions are within the Blog. 9 | 10 | ### Solution architecture 11 | ![Architecture](https://github.com/aws-samples/aws-security-hub-prowler-integrations/blob/master/Architecture.jpg) 12 | The integration works as follows: 13 | 1. A time-based CloudWatch Event will start the Fargate task on a schedule 14 | 2. Fargate will pull a Docker image from Amazon Elastic Container Registry (ECR) that contains Prowler and Python scripts used to load an Amazon DynamoDB table. 15 | 3. Prowler scans your AWS infrastructure and writes the scan results to a CSV file 16 | 4. Python scripts convert the CSV to JSON and load DynamoDB with formatted Prowler findings 17 | 5. A DynamoDB stream invokes an AWS Lambda function 18 | 6. Lambda maps Prowler findings into the Amazon Security Finding Format (ASFF) before importing them to Security Hub 19 | 20 | ### Where is the information from the Prowler check? 21 | That will appear in the Description of the finding 22 | 23 | ## License 24 | 25 | This library is licensed under the MIT-0 License. See the LICENSE file. --------------------------------------------------------------------------------