New folder structure phase 1
57
contrib/cloudshell/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# ShortCut script: run Prowler and ScoutSuite in Customer's environment using AWS CloudShell
|
||||
|
||||
### Use Case:
|
||||
|
||||
Customers look to use multiple auditing tools in order to provide quick assessments about their AWS environments. These tools allow for reports to be generated for review by the customer and appropriate teams, which in turns helps them begin security remediation efforts.
|
||||
|
||||
Prowler and ScoutSuite are two publicly available security auditing tools that provide comprehensive reports for customers using AWS.
|
||||
|
||||
ShortCut is a mechanism for customers to use to run both Prowler and ScoutSuite within an AWS account, using AWS CloudShell. When customers use ShortCut, this allows for customers to quickly perform an audit on their environment, without having to provision IAM Access Keys or EC2 instances.
|
||||
|
||||
### Prerequisites:
|
||||
|
||||
Note: The current version of this script is ran in a single account.
|
||||
|
||||
In order to use CloudShell, the customer will need the following permissions within their AWS Account:
|
||||
```
|
||||
cloudshell:*
|
||||
```
|
||||
|
||||
In addition, the following IAM Policies are needed in order to run ScoutSuite & Prowler:
|
||||
```
|
||||
arn:aws:iam::aws:policy/SecurityAudit
|
||||
arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
|
||||
```
|
||||
|
||||
### Instructions
|
||||
1. Log into the AWS Console
|
||||
2. Go to AWS CloudShell. There's a screenshot of the AWS CloudShell icon below, or if you're logged into AWS already, you can click this link: console.aws.amazon.com/cloudshell
|
||||
|
||||

|
||||
|
||||
3. Once the session begins, upload the shortcut.sh file into the AWS CloudShell session by selecting Actions -> Upload File.
|
||||
|
||||

|
||||
|
||||
4. Once the file is uploaded, run the following command within your AWS CloudShell session:
|
||||
```
|
||||
bash shortcut.sh
|
||||
```
|
||||
5. The results for Prowler and ScoutSuite will be located in the following directory:
|
||||
```
|
||||
/home/cloudshell-user/<account number>-results
|
||||
```
|
||||
6. You can check the status of each screen session by typing the following commands:
|
||||
```
|
||||
# Prowler:
|
||||
screen -r prowler
|
||||
# ScoutSuite
|
||||
screen -r scoutsuite
|
||||
```
|
||||
7. To download the results from AWS CloudShell, select Actions -> Download File.
|
||||
|
||||

|
||||
|
||||
8. In the Download File prompt, use the file path and file name to download the results.
|
||||
|
||||

|
||||
BIN
contrib/cloudshell/screenshots/action_download_icon.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
contrib/cloudshell/screenshots/action_upload_icon.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
contrib/cloudshell/screenshots/cloudshell_icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
contrib/cloudshell/screenshots/download_prompt.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
36
contrib/cloudshell/shortcut.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ShortCut - Run Prowler and ScoutSuite in Customer's environment using AWS CloudShell
|
||||
# DozerCat - Team DragonCat - AWS
|
||||
|
||||
# Package Prerequisites
|
||||
sudo yum update -y
|
||||
sudo yum install python3 -y
|
||||
sudo yum install screen -y
|
||||
sudo yum install zip -y
|
||||
|
||||
# Variable and Environment Prerequisites
|
||||
account=$(aws sts get-caller-identity | jq --raw-output '.Account')
|
||||
mkdir ${account}-results
|
||||
|
||||
# Prowler
|
||||
cd ~
|
||||
git clone https://github.com/prowler-cloud/prowler
|
||||
pip3 install detect-secrets --user
|
||||
cd prowler
|
||||
screen -dmS prowler sh -c "./prowler -M csv,html;cd ~;zip -r ${account}-results/prowler-${account}.zip /home/cloudshell-user/prowler/output"
|
||||
|
||||
# ScoutSuite
|
||||
cd ~
|
||||
git clone https://github.com/nccgroup/ScoutSuite
|
||||
cd ScoutSuite
|
||||
sudo yum install python-pip -y
|
||||
sudo pip install virtualenv
|
||||
virtualenv -p python3 venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
sleep 2
|
||||
screen -dmS scoutsuite sh -c "python scout.py aws;cd ~;zip -r ${account}-results/scoutsuite-${account}.zip /home/cloudshell-user/ScoutSuite/scoutsuite-report"
|
||||
|
||||
# Check on screen sessions
|
||||
screen -ls
|
||||
383
contrib/codebuild/codebuild-prowler-audit-account-cfn.yaml
Normal file
@@ -0,0 +1,383 @@
|
||||
---
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Creates a CodeBuild project to audit an AWS account with Prowler and stores the html report in a S3 bucket. This will run onece at the beginning and on a schedule afterwards. Partial contribution from https://github.com/stevecjones
|
||||
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, HTML reports in S3 are not deleted'
|
||||
Type: Number
|
||||
Default: 3
|
||||
AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 180, 365]
|
||||
|
||||
ProwlerOptions:
|
||||
Description: 'Options to pass to Prowler command, make sure at least -M junit-xml is used for CodeBuild reports. Use -r for the region to send API queries, -f to filter only one region, -M output formats, -c for comma separated checks, for all checks do not use -c or -g, for more options see -h. For a complete assessment use "-M text,junit-xml,html,csv,json", for SecurityHub integration use "-r region -f region -M text,junit-xml,html,csv,json,json-asff -S -q"'
|
||||
Type: String
|
||||
# Prowler command below runs a set of checks, configure it base on your needs, no options will run all regions all checks.
|
||||
# option -M junit-xml is requirede in order to get the report in CodeBuild.
|
||||
Default: -r eu-west-1 -f eu-west-1 -M text,junit-xml,html,csv,json -c check11,check12,check13,check14
|
||||
|
||||
ProwlerScheduler:
|
||||
Description: The time when Prowler will run in cron format. Default is daily at 22:00h or 10PM 'cron(0 22 * * ? *)', for every 5 hours also works 'rate(5 hours)'. More info here https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html.
|
||||
Type: String
|
||||
Default: 'cron(0 22 * * ? *)'
|
||||
|
||||
Resources:
|
||||
CodeBuildStartBuild:
|
||||
Type: 'Custom::CodeBuildStartBuild'
|
||||
DependsOn:
|
||||
- CodeBuildLogPolicy
|
||||
- CodeBuildStartLogPolicy
|
||||
Properties:
|
||||
Build: !Ref ProwlerCodeBuild
|
||||
ServiceToken: !GetAtt CodeBuildStartBuildLambda.Arn
|
||||
|
||||
CodeBuildStartBuildLambdaRole:
|
||||
Type: 'AWS::IAM::Role'
|
||||
Properties:
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: !Sub lambda.${AWS::URLSuffix}
|
||||
Action: 'sts:AssumeRole'
|
||||
Description: !Sub 'DO NOT DELETE - Used by Lambda. Created by CloudFormation Stack ${AWS::StackId}'
|
||||
Policies:
|
||||
- PolicyName: StartBuildInline
|
||||
PolicyDocument:
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: 'codebuild:StartBuild'
|
||||
Resource: !GetAtt ProwlerCodeBuild.Arn
|
||||
|
||||
CodeBuildStartBuildLambda:
|
||||
Type: 'AWS::Lambda::Function'
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W58
|
||||
reason: 'This Lambda has permissions to write Logs'
|
||||
- id: W89
|
||||
reason: 'VPC is not needed'
|
||||
- id: W92
|
||||
reason: 'ReservedConcurrentExecutions not needed'
|
||||
Properties:
|
||||
Handler: index.lambda_handler
|
||||
MemorySize: 128
|
||||
Role: !Sub ${CodeBuildStartBuildLambdaRole.Arn}
|
||||
Timeout: 120
|
||||
Runtime: python3.9
|
||||
Code:
|
||||
ZipFile: |
|
||||
import boto3
|
||||
import cfnresponse
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
def lambda_handler(event,context):
|
||||
props = event['ResourceProperties']
|
||||
codebuild_client = boto3.client('codebuild')
|
||||
|
||||
if (event['RequestType'] == 'Create' or event['RequestType'] == 'Update'):
|
||||
try:
|
||||
response = codebuild_client.start_build(projectName=props['Build'])
|
||||
print(response)
|
||||
print("Respond: SUCCESS")
|
||||
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
|
||||
except Exception as ex:
|
||||
print(ex.response['Error']['Message'])
|
||||
cfnresponse.send(event, context, cfnresponse.FAILED, ex.response)
|
||||
else:
|
||||
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
|
||||
|
||||
CodeBuildStartLogGroup:
|
||||
Type: 'AWS::Logs::LogGroup'
|
||||
DeletionPolicy: Delete
|
||||
UpdateReplacePolicy: Delete
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W84
|
||||
reason: 'KMS encryption is not needed.'
|
||||
Properties:
|
||||
LogGroupName: !Sub '/aws/lambda/${CodeBuildStartBuildLambda}'
|
||||
RetentionInDays: !Ref LogsRetentionInDays
|
||||
|
||||
CodeBuildStartLogPolicy:
|
||||
Type: AWS::IAM::Policy
|
||||
Properties:
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action:
|
||||
- logs:CreateLogStream
|
||||
- logs:PutLogEvents
|
||||
Effect: Allow
|
||||
Resource: !GetAtt CodeBuildStartLogGroup.Arn
|
||||
PolicyName: LogGroup
|
||||
Roles:
|
||||
- !Ref CodeBuildStartBuildLambdaRole
|
||||
|
||||
ArtifactBucket:
|
||||
Type: AWS::S3::Bucket
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W35
|
||||
reason: 'S3 Access Logging is not needed'
|
||||
Properties:
|
||||
Tags:
|
||||
- Key: Name
|
||||
Value: !Sub '${ServiceName}-${AWS::AccountId}-S3-Prowler-${AWS::StackName}'
|
||||
BucketName: !Sub '${ServiceName}-reports-${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: !Sub '${ArtifactBucket.Arn}/*'
|
||||
Sid: S3ForceSSL
|
||||
- Action: 's3:PutObject'
|
||||
Condition:
|
||||
'Null':
|
||||
s3:x-amz-server-side-encryption: true
|
||||
Effect: Deny
|
||||
Principal: '*'
|
||||
Resource: !Sub '${ArtifactBucket.Arn}/*'
|
||||
Sid: DenyUnEncryptedObjectUploads
|
||||
|
||||
CodeBuildServiceRole:
|
||||
Type: AWS::IAM::Role
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W11
|
||||
reason: 'Role complies with the least privilege principle.'
|
||||
Properties:
|
||||
Description: !Sub 'DO NOT DELETE - Used by CodeBuild. Created by CloudFormation Stack ${AWS::StackId}'
|
||||
ManagedPolicyArns:
|
||||
- !Sub 'arn:${AWS::Partition}:iam::aws:policy/job-function/SupportUser'
|
||||
- !Sub 'arn:${AWS::Partition}:iam::aws:policy/job-function/ViewOnlyAccess'
|
||||
- !Sub 'arn:${AWS::Partition}:iam::aws:policy/SecurityAudit'
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action: 'sts:AssumeRole'
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: !Sub codebuild.${AWS::URLSuffix}
|
||||
Policies:
|
||||
- PolicyName: S3
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action:
|
||||
- s3:PutObject
|
||||
- s3:GetObject
|
||||
- s3:GetObjectVersion
|
||||
- s3:GetBucketAcl
|
||||
- s3:GetBucketLocation
|
||||
Effect: Allow
|
||||
Resource: !Sub '${ArtifactBucket.Arn}/*'
|
||||
- PolicyName: ProwlerAdditions
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action:
|
||||
- ds:ListAuthorizedApplications
|
||||
- ec2:GetEbsEncryptionByDefault
|
||||
- ecr:Describe*
|
||||
- elasticfilesystem:DescribeBackupPolicy
|
||||
- glue:GetConnections
|
||||
- glue:GetSecurityConfiguration
|
||||
- glue:SearchTables
|
||||
- lambda:GetFunction
|
||||
- s3:GetAccountPublicAccessBlock
|
||||
- shield:DescribeProtection
|
||||
- shield:GetSubscriptionState
|
||||
- ssm:GetDocument
|
||||
- support:Describe*
|
||||
- tag:GetTagKeys
|
||||
Effect: Allow
|
||||
Resource: '*'
|
||||
- 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::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/*'
|
||||
- PolicyName: SecurityHubBatchImportFindings
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action: securityhub:BatchImportFindings
|
||||
Effect: Allow
|
||||
Resource: !Sub 'arn:${AWS::Partition}:securityhub:${AWS::Region}::product/prowler/prowler'
|
||||
|
||||
CodeBuildLogPolicy:
|
||||
Type: AWS::IAM::Policy
|
||||
Properties:
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action:
|
||||
- logs:CreateLogStream
|
||||
- logs:PutLogEvents
|
||||
Effect: Allow
|
||||
Resource: !GetAtt ProwlerLogGroup.Arn
|
||||
PolicyName: LogGroup
|
||||
Roles:
|
||||
- !Ref CodeBuildServiceRole
|
||||
|
||||
CodeBuildAssumePolicy:
|
||||
Type: AWS::IAM::Policy
|
||||
Properties:
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action: 'sts:AssumeRole'
|
||||
Effect: Allow
|
||||
Resource: !GetAtt CodeBuildServiceRole.Arn
|
||||
PolicyName: AssumeRole
|
||||
Roles:
|
||||
- !Ref CodeBuildServiceRole
|
||||
|
||||
ProwlerCodeBuild:
|
||||
Type: AWS::CodeBuild::Project
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W32
|
||||
reason: 'KMS encryption is not needed.'
|
||||
Properties:
|
||||
Artifacts:
|
||||
Type: NO_ARTIFACTS
|
||||
ConcurrentBuildLimit: 1
|
||||
Source:
|
||||
GitCloneDepth: 1
|
||||
Location: https://github.com/prowler-cloud/prowler
|
||||
Type: GITHUB
|
||||
ReportBuildStatus: false
|
||||
BuildSpec: |
|
||||
version: 0.2
|
||||
phases:
|
||||
install:
|
||||
runtime-versions:
|
||||
python: 3.9
|
||||
commands:
|
||||
- echo "Installing Prowler and dependencies..."
|
||||
- pip3 install detect-secrets
|
||||
build:
|
||||
commands:
|
||||
- echo "Running Prowler as ./prowler $PROWLER_OPTIONS"
|
||||
- ./prowler $PROWLER_OPTIONS
|
||||
post_build:
|
||||
commands:
|
||||
- echo "Uploading reports to S3..."
|
||||
- aws s3 cp --sse AES256 output/ s3://$BUCKET_REPORT/ --recursive
|
||||
- echo "Done!"
|
||||
reports:
|
||||
prowler:
|
||||
files:
|
||||
- '**/*'
|
||||
base-directory: 'junit-reports'
|
||||
file-format: JunitXml
|
||||
Environment:
|
||||
# AWS CodeBuild free tier includes 100 build minutes of BUILD_GENERAL1_SMALL per month.
|
||||
# BUILD_GENERAL1_SMALL: Use up to 3 GB memory and 2 vCPUs for builds. $0.005/minute.
|
||||
# BUILD_GENERAL1_MEDIUM: Use up to 7 GB memory and 4 vCPUs for builds. $0.01/minute.
|
||||
# BUILD_GENERAL1_LARGE: Use up to 15 GB memory and 8 vCPUs for builds. $0.02/minute.
|
||||
# BUILD_GENERAL1_2XLARGE: Use up to 144 GB memory and 72 vCPUs for builds. $0.20/minute.
|
||||
ComputeType: "BUILD_GENERAL1_SMALL"
|
||||
Image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
|
||||
Type: "LINUX_CONTAINER"
|
||||
EnvironmentVariables:
|
||||
- Name: BUCKET_REPORT
|
||||
Value: !Ref ArtifactBucket
|
||||
Type: PLAINTEXT
|
||||
- Name: PROWLER_OPTIONS
|
||||
Value: !Ref ProwlerOptions
|
||||
Type: PLAINTEXT
|
||||
Description: Run Prowler assessment
|
||||
ServiceRole: !GetAtt CodeBuildServiceRole.Arn
|
||||
TimeoutInMinutes: 300
|
||||
|
||||
ProwlerLogGroup:
|
||||
Type: 'AWS::Logs::LogGroup'
|
||||
DeletionPolicy: Delete
|
||||
UpdateReplacePolicy: Delete
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W84
|
||||
reason: 'KMS encryption is not needed.'
|
||||
Properties:
|
||||
LogGroupName: !Sub '/aws/codebuild/${ProwlerCodeBuild}'
|
||||
RetentionInDays: !Ref LogsRetentionInDays
|
||||
|
||||
EventBridgeServiceRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: !Sub 'DO NOT DELETE - Used by EventBridge. Created by CloudFormation Stack ${AWS::StackId}'
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Action: 'sts:AssumeRole'
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: !Sub events.${AWS::URLSuffix}
|
||||
Policies:
|
||||
- PolicyName: CodeBuild
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action: 'codebuild:StartBuild'
|
||||
Resource: !GetAtt ProwlerCodeBuild.Arn
|
||||
|
||||
ProwlerSchedule:
|
||||
Type: 'AWS::Events::Rule'
|
||||
Properties:
|
||||
Description: A schedule to trigger Prowler in CodeBuild
|
||||
ScheduleExpression: !Ref ProwlerScheduler
|
||||
State: ENABLED
|
||||
Targets:
|
||||
- Arn: !GetAtt ProwlerCodeBuild.Arn
|
||||
Id: ProwlerSchedule
|
||||
RoleArn: !GetAtt EventBridgeServiceRole.Arn
|
||||
|
||||
Outputs:
|
||||
ArtifactBucketName:
|
||||
Description: Artifact Bucket Name
|
||||
Value: !Ref ArtifactBucket
|
||||
233
contrib/html/generate-html-from-csv.sh
Executable file
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
|
||||
## This script helps to generate a single html report from a single or multiple csv
|
||||
# output reports.
|
||||
# I use it when I want to visualize multiple accounts reports in a single view.
|
||||
# Report information and Assessment Summary will be empty due to the variables
|
||||
# that are not set here.
|
||||
|
||||
## First: Remove the CSV header from each output report.
|
||||
|
||||
## Second: If you want to aggretate all csv files in you can do like this:
|
||||
# find . -type f -name '*.csv' -exec cat {} + > prowler-output-unified-csv.file
|
||||
# use .file instead of .csv unless you want to get into an infinite loop ;)
|
||||
|
||||
## Third: Usage ./generate-html-from-csv.sh aggregated-reports-csv.file
|
||||
|
||||
|
||||
OUTPUT_FILE_NAME="report-unified-csv"
|
||||
EXTENSION_HTML="html"
|
||||
INPUT=$1
|
||||
IFS=',' # used inside the while loop for csv delimiter
|
||||
HTML_LOGO_URL="https://github.com/prowler-cloud/prowler/"
|
||||
HTML_LOGO_IMG="https://raw.githubusercontent.com/prowler-cloud/prowler/master/util/html/prowler-logo-new.png"
|
||||
|
||||
|
||||
[ ! -f $INPUT ] && { echo "$INPUT file not found"; exit 99; }
|
||||
|
||||
addHtmlHeader() {
|
||||
if [[ $PROFILE == "" ]];then
|
||||
PROFILE="ENV"
|
||||
fi
|
||||
if [[ -z $HTML_REPORT_INIT ]]; then
|
||||
cat <<EOF
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<!-- Required meta tags -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.21/b-1.6.2/sl-1.3.1/datatables.min.css"/>
|
||||
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||
<script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.21/b-1.6.2/sl-1.3.1/datatables.min.js"></script>
|
||||
<title>Prowler - AWS Security Assesments</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-xl sticky-top navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="#">Prowler - Security Assesments in AWS</a>
|
||||
</nav>
|
||||
<div class="container-fluid">
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Report Information
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-md-auto">
|
||||
<b>Version:</b> $PROWLER_VERSION
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>Parameters used:</b> $PROWLER_PARAMETERS
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>Date:</b> $TIMESTAMP
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<a href="$HTML_LOGO_URL"><img src="$HTML_LOGO_IMG"
|
||||
alt="prowler-logo"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Assesment Summary
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<b>AWS Account:</b> $ACCOUNT_NUM
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>AWS-CLI Profile:</b> $PROFILE
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>API Region:</b> $REGION
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>User Id:</b> $USER_ID
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<b>Caller Identity ARN:</b> $CALLER_ARN
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
* Sortable columns are CheckID (default) and Result
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-12">
|
||||
<table class="table compact stripe row-border ordering" id="findingsTable" data-order='[[ 5, "asc" ]]' data-page-length='100'>
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th style="align-content:center" scope="col">Status</th>
|
||||
<th scope="col">Result</th>
|
||||
<th scope="col">Severity</th>
|
||||
<th scope="col">AccountID</th>
|
||||
<th scope="col">Region</th>
|
||||
<th scope="col">Compliance</th>
|
||||
<th scope="col">Service</th>
|
||||
<th scope="col">CheckID</th>
|
||||
<th style="width:40%" scope="col">Check Title</th>
|
||||
<th style="width:40%" scope="col">Check Output</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
EOF
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
addHtmlFooter() {
|
||||
cat <<EOF
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Table search and paginator -->
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js" integrity="sha384-1CmrxMRARb6aLqgBO7yyAxTOQE2AKb9GfXnEo760AUcUmFx3ibVJJAzGytlQcNXd" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<!-- JQuery-->
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<!-- dataTables-->
|
||||
<script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
|
||||
<script>
|
||||
\$(document).ready(function(){ \$('#findingsTable').dataTable( { "lengthMenu": [ [50, 100, -1], [50, 100, "All"] ], "ordering": true } ); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
unset HTML_REPORT_INIT
|
||||
}
|
||||
|
||||
addHtmlHeader > ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
while IFS=, read -r PROFILE ACCOUNT_NUM REPREGION TITLE_ID RESULT SCORED LEVEL TITLE_TEXT NOTES ASFF_COMPLIANCE_TYPE CHECK_SEVERITY CHECK_SERVICENAME;do
|
||||
if [[ $RESULT == "INFO" ]]; then
|
||||
echo '<tr class="table-info">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-info-circle"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>INFO</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$NOTES'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
fi
|
||||
if [[ $RESULT == "PASS" ]]; then
|
||||
echo '<tr class="p-3 mb-2 bg-success">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-thumbs-up"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>PASS</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$NOTES'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
fi
|
||||
if [[ $RESULT == "FAIL" ]]; then
|
||||
echo '<tr class="table-danger" >' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td> <i class="fas fa-thumbs-down"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>FAIL</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$NOTES'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
fi
|
||||
if [[ $RESULT == "WARNING" ]]; then
|
||||
echo '<tr class="table-warning">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-exclamation-triangle"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>WARN</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$NOTES'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
fi
|
||||
done < $INPUT
|
||||
addHtmlFooter >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
|
||||
|
||||
|
||||
BIN
contrib/html/prowler-logo-new.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
contrib/html/prowler-logo.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
11
contrib/k8s/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## K8S - Cronjob
|
||||
Simple instructions to add a cronjob on K8S to execute a prowler and save the results on AWS S3.
|
||||
|
||||
### Files:
|
||||
cronjob.yml ---> is a **cronjob** for K8S, you must set the frequency and probes from yours scans \
|
||||
secret.yml -----> is a **secret** file with AWS ID/Secret and the name of bucket
|
||||
|
||||
### To apply:
|
||||
|
||||
`$ kubectl -f cronjob.yml` \
|
||||
`$ kubectl -f secret.yml`
|
||||
40
contrib/k8s/cronjob.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
apiVersion: batch/v1beta1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: devsecops-prowler-cronjob-secret
|
||||
namespace: defectdojo
|
||||
spec:
|
||||
#Cron Time is set according to server time, ensure server time zone and set accordingly.
|
||||
successfulJobsHistoryLimit: 2
|
||||
failedJobsHistoryLimit: 1
|
||||
schedule: "5 3 * * 0,2,4"
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: prowler
|
||||
image: toniblyx/prowler:latest
|
||||
imagePullPolicy: Always
|
||||
command:
|
||||
- "./prowler"
|
||||
args: [ "-g", "hipaa", "-M", "csv,json,html", "-B", "$(awsS3Bucket)" ]
|
||||
env:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: devsecops-prowler-cronjob-secret
|
||||
key: awsId
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: devsecops-prowler-cronjob-secret
|
||||
key: awsSecretKey
|
||||
- name: awsS3Bucket
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: devsecops-prowler-cronjob-secret
|
||||
key: awsS3Bucket
|
||||
imagePullPolicy: IfNotPresent
|
||||
restartPolicy: OnFailure
|
||||
backoffLimit: 3
|
||||
10
contrib/k8s/secret.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: devsecops-prowler-cronjob-secret
|
||||
namespace: defectdojo
|
||||
type: Opaque
|
||||
stringData:
|
||||
awsId: myAWSSecretID
|
||||
awsSecretKey: myAWSSecretKey
|
||||
awsS3Bucket: myAWSS3Bucket
|
||||
3
contrib/multi-account-securityhub/.awsvariables
Normal file
@@ -0,0 +1,3 @@
|
||||
export ROLE=ProwlerXA-Role
|
||||
export PARALLEL_ACCOUNTS=1
|
||||
export REGION=us-east-1
|
||||
45
contrib/multi-account-securityhub/Dockerfile
Normal file
@@ -0,0 +1,45 @@
|
||||
# Build command
|
||||
# docker build --platform=linux/amd64 --no-cache -t prowler:latest .
|
||||
|
||||
FROM public.ecr.aws/amazonlinux/amazonlinux:2022
|
||||
|
||||
ARG PROWLERVER=2.9.0
|
||||
ARG USERNAME=prowler
|
||||
ARG USERID=34000
|
||||
|
||||
# Install Dependencies
|
||||
RUN \
|
||||
dnf update -y && \
|
||||
dnf install -y bash file findutils git jq python3 python3-pip \
|
||||
python3-setuptools python3-wheel shadow-utils tar unzip which && \
|
||||
dnf remove -y awscli && \
|
||||
dnf clean all && \
|
||||
useradd -l -s /bin/sh -U -u ${USERID} ${USERNAME} && \
|
||||
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
|
||||
unzip awscliv2.zip && \
|
||||
./aws/install && \
|
||||
pip3 install --no-cache-dir --upgrade pip && \
|
||||
pip3 install --no-cache-dir "git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets" && \
|
||||
rm -rf aws awscliv2.zip /var/cache/dnf
|
||||
|
||||
# Place script and env vars
|
||||
COPY .awsvariables run-prowler-securityhub.sh /
|
||||
|
||||
# Installs prowler and change permissions
|
||||
RUN \
|
||||
curl -L "https://github.com/prowler-cloud/prowler/archive/refs/tags/${PROWLERVER}.tar.gz" -o "prowler.tar.gz" && \
|
||||
tar xvzf prowler.tar.gz && \
|
||||
rm -f prowler.tar.gz && \
|
||||
mv prowler-${PROWLERVER} prowler && \
|
||||
chown ${USERNAME}:${USERNAME} /run-prowler-securityhub.sh && \
|
||||
chmod 500 /run-prowler-securityhub.sh && \
|
||||
chown ${USERNAME}:${USERNAME} /.awsvariables && \
|
||||
chmod 400 /.awsvariables && \
|
||||
chown ${USERNAME}:${USERNAME} -R /prowler && \
|
||||
chmod +x /prowler/prowler
|
||||
|
||||
# Drop to user
|
||||
USER ${USERNAME}
|
||||
|
||||
# Run script
|
||||
ENTRYPOINT ["/run-prowler-securityhub.sh"]
|
||||
94
contrib/multi-account-securityhub/README.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Example Solution: Serverless Organizational Prowler Deployment with SecurityHub
|
||||
|
||||
Deploys [Prowler](https://github.com/prowler-cloud/prowler) with AWS Fargate to assess all Accounts in an AWS Organization on a schedule, and sends the results to Security Hub.
|
||||
|
||||
## Context
|
||||
Originally based on [org-multi-account](https://github.com/prowler-cloud/prowler/tree/master/util/org-multi-account), but changed in the following ways:
|
||||
|
||||
- No HTML reports and no S3 buckets
|
||||
- Findings sent directly to Security Hub using the native integration
|
||||
- AWS Fargate Task with EventBridge Rule instead of EC2 instance with cronjob
|
||||
- Based on amazonlinux:2022 to leverage "wait -n" for improved parallelization as new jobs are launched as one finishes
|
||||
|
||||
## Architecture Explanation
|
||||
|
||||
The solution is designed to be very simple. Prowler is run via an ECS Task definition that launches a single Fargate container. This Task Definition is executed on a schedule using an EventBridge Rule.
|
||||
|
||||
## CloudFormation Templates
|
||||
|
||||
### CF-Prowler-IAM.yml
|
||||
Creates the following IAM Roles:
|
||||
|
||||
1. **ECSExecutionRole**: Required for the Task Definition to be able to fetch the container image from ECR and launch the container.
|
||||
2. **ProwlerTaskRole**: Role that the container itself runs with. It allows it to assume the ProwlerCrossAccountRole.
|
||||
3. **ECSEventRoleName**: Required for the EventBridge Rule to execute the Task Definition.
|
||||
|
||||
### CF-Prowler-ECS.yml
|
||||
Creates the following resources:
|
||||
|
||||
1. **ProwlerECSCluster**: Cluster to be used to execute the Task Definition.
|
||||
2. **ProwlerECSCloudWatchLogsGroup**: Log group for the Prowler container logs. This is required because it's the only log driver supported by Fargate. The Prowler executable logs are suppressed to prevent unnecessary logs, but error logs are kept for debugging.
|
||||
3. **ProwlerECSTaskDefinition**: Task Definition for the Fargate container. CPU and memory can be increased as needed. In my experience, 1 CPU per parallel Prowler job is ideal, but further performance testing may be required to find the optimal configuration for a specific organization. Enabling container insights helps a lot with this.
|
||||
4. **ProwlerSecurityGroup**: Security Group for the container. It only allows TCP 443 outbound, as it is the only port needed for awscli.
|
||||
5. **ProwlerTaskScheduler**: EventBridge Rule that schedules the execution of the Task Definition. The cron expression is specified as a CloudFormation template parameter.
|
||||
|
||||
### CF-Prowler-CrossAccountRole.yml
|
||||
Creates the cross account IAM Role required for Prowler to run. Deploy it as StackSet in every account in the AWS Organization.
|
||||
|
||||
## Docker Container
|
||||
|
||||
### Dockerfile
|
||||
The Dockerfile does the following:
|
||||
1. Uses amazonlinux:2022 as a base.
|
||||
2. Downloads required dependencies.
|
||||
3. Copies the .awsvariables and run-prowler-securityhub.sh files into the root.
|
||||
4. Downloads the specified version of Prowler as recommended in the release notes.
|
||||
5. Assigns permissions to a lower privileged user and then drops to it.
|
||||
6. Runs the script.
|
||||
|
||||
### .awsvariables
|
||||
The .awsvariables file is used to pass required configuration to the script:
|
||||
|
||||
1. **ROLE**: The cross account Role to be assumed for the Prowler assessments.
|
||||
2. **PARALLEL_ACCOUNTS**: The number of accounts to be scanned in parallel.
|
||||
3. **REGION**: Region where Prowler will run its assessments.
|
||||
|
||||
### run-prowler-securityhub.sh
|
||||
The script gets the list of accounts in AWS Organizations, and then executes Prowler as a job for each account, up to PARALLEL_ACCOUNT accounts at the same time.
|
||||
The logs that are generated and sent to Cloudwatch are error logs, and assessment start and finish logs.
|
||||
|
||||
## Instructions
|
||||
1. Create a Private ECR Repository in the account that will host the Prowler container. The Audit account is recommended, but any account can be used.
|
||||
2. Configure the .awsvariables file. Note the ROLE name chosen as it will be the CrossAccountRole.
|
||||
3. Follow the steps from "View Push Commands" to build and upload the container image. You need to have Docker and AWS CLI installed, and use the cli to login to the account first. After upload note the Image URI, as it is required for the CF-Prowler-ECS template.
|
||||
4. Make sure SecurityHub is enabled in every account in AWS Organizations, and that the SecurityHub integration is enabled as explained in [Prowler - Security Hub Integration](https://github.com/prowler-cloud/prowler#security-hub-integration)
|
||||
5. Deploy **CF-Prowler-CrossAccountRole.yml** in the Master Account as a single stack. You will have to choose the CrossAccountRole name (ProwlerXA-Role by default) and the ProwlerTaskRoleName (ProwlerECSTask-Role by default)
|
||||
6. Deploy **CF-Prowler-CrossAccountRole.yml** in every Member Account as a StackSet. Choose the same CrossAccountName and ProwlerTaskRoleName as the previous step.
|
||||
7. Deploy **CF-Prowler-IAM.yml** in the account that will host the Prowler container (the same from step 1). The following template parameters must be provided:
|
||||
- **ProwlerCrossAccountRoleName**: Name of the from CF-Prowler-CrossAccountRole (default ProwlerXA-Role).
|
||||
- **ECSExecutionRoleName**: Name for the ECS Task Execution Role (default ECSTaskExecution-Role).
|
||||
- **ProwlerTaskRoleName**: Name for the ECS Prowler Task Role (default ProwlerECSTask-Role).
|
||||
- **ECSEventRoleName**: Name for the Eventbridge Task Role (default ProwlerEvents-Role).
|
||||
8. Deploy **CF-Prowler-ECS.yml** in the account that will host the Prowler container (the same from step 1). The following template parameters must be provided:
|
||||
- **ProwlerClusterName**: Name for the ECS Cluster (default ProwlerCluster)
|
||||
- **ProwlerContainerName**: Name for the Prowler container (default prowler)
|
||||
- **ProwlerContainerInfo**: ECR URI from step 1.
|
||||
- **ProwlerECSLogGroupName**: CloudWatch Log Group name (default /aws/ecs/SecurityHub-Prowler)
|
||||
- **SecurityGroupVPCId**: VPC ID for the VPC where the container will run.
|
||||
- **ProwlerScheduledSubnet1 and 2**: Subnets IDs from the VPC specified. Choose private subnets if possible.
|
||||
- **ECSExecutionRole**: ECS Execution Task Role ARN from CF-Prowler-IAM outputs.
|
||||
- **ProwlerTaskRole**: Prowler ECS Task Role ARN from CF-Prowler-IAM outputs.
|
||||
- **ECSEventRole**: Eventbridge Task Role ARN from CF-Prowler-IAM outputs.
|
||||
- **CronExpression**: Valid Cron Expression for the scheduling of the Task Definition.
|
||||
9. Verify that Prowler runs correctly by checking the CloudWatch logs after the scheduled task is executed.
|
||||
|
||||
---
|
||||
## Troubleshooting
|
||||
|
||||
If you permission find errors in the CloudWatch logs, the culprit might be a [Service Control Policy (SCP)](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html). You will need to exclude the Prowler Cross Account Role from those SCPs.
|
||||
|
||||
---
|
||||
## Upgrading Prowler
|
||||
|
||||
Prowler version is controlled by the PROWLERVER argument in the Dockerfile, change it to the desired version and follow the ECR Push Commands to update the container image.
|
||||
Old images can be deleted from the ECR Repository after the new image is confirmed to work. They will show as "untagged" as only one image can hold the "latest" tag.
|
||||
86
contrib/multi-account-securityhub/run-prowler-securityhub.sh
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# Run Prowler against All AWS Accounts in an AWS Organization
|
||||
|
||||
# Change Directory (rest of the script, assumes you're in the root directory)
|
||||
cd / || exit
|
||||
|
||||
# Show Prowler Version
|
||||
./prowler/prowler -V
|
||||
|
||||
# Source .awsvariables
|
||||
# shellcheck disable=SC1091
|
||||
source .awsvariables
|
||||
|
||||
# Get Values from Environment Variables
|
||||
echo "ROLE: $ROLE"
|
||||
echo "PARALLEL_ACCOUNTS: $PARALLEL_ACCOUNTS"
|
||||
echo "REGION: $REGION"
|
||||
|
||||
# Function to unset AWS Profile Variables
|
||||
unset_aws() {
|
||||
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
unset_aws
|
||||
|
||||
# Find THIS Account AWS Number
|
||||
CALLER_ARN=$(aws sts get-caller-identity --output text --query "Arn")
|
||||
PARTITION=$(echo "$CALLER_ARN" | cut -d: -f2)
|
||||
THISACCOUNT=$(echo "$CALLER_ARN" | cut -d: -f5)
|
||||
echo "THISACCOUNT: $THISACCOUNT"
|
||||
echo "PARTITION: $PARTITION"
|
||||
|
||||
# Function to Assume Role to THIS Account & Create Session
|
||||
this_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$THISACCOUNT":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Find AWS Master Account
|
||||
this_account_session
|
||||
AWSMASTER=$(aws organizations describe-organization --query Organization.MasterAccountId --output text)
|
||||
echo "AWSMASTER: $AWSMASTER"
|
||||
|
||||
# Function to Assume Role to Master Account & Create Session
|
||||
master_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$AWSMASTER":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Lookup All Accounts in AWS Organization
|
||||
master_account_session
|
||||
ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[*].Id --output text)
|
||||
|
||||
# Run Prowler against Accounts in AWS Organization
|
||||
echo "AWS Accounts in Organization"
|
||||
echo "$ACCOUNTS_IN_ORGS"
|
||||
for accountId in $ACCOUNTS_IN_ORGS; do
|
||||
# shellcheck disable=SC2015
|
||||
test "$(jobs | wc -l)" -ge $PARALLEL_ACCOUNTS && wait -n || true
|
||||
{
|
||||
START_TIME=$SECONDS
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
# Run Prowler
|
||||
echo -e "Assessing AWS Account: $accountId, using Role: $ROLE on $(date)"
|
||||
# Pipe stdout to /dev/null to reduce unnecessary Cloudwatch logs
|
||||
./prowler/prowler -R "$ROLE" -A "$accountId" -M json-asff -q -S -f "$REGION" > /dev/null
|
||||
TOTAL_SEC=$((SECONDS - START_TIME))
|
||||
printf "Completed AWS Account: $accountId in %02dh:%02dm:%02ds" $((TOTAL_SEC / 3600)) $((TOTAL_SEC % 3600 / 60)) $((TOTAL_SEC % 60))
|
||||
echo ""
|
||||
} &
|
||||
done
|
||||
|
||||
# Wait for All Prowler Processes to finish
|
||||
wait
|
||||
echo "Prowler Assessments Completed against All Accounts in AWS Organization"
|
||||
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
@@ -0,0 +1,97 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create the Cross-Account IAM Prowler Role
|
||||
Metadata:
|
||||
AWS::CloudFormation::Interface:
|
||||
ParameterGroups:
|
||||
- Label:
|
||||
default: ECS Settings
|
||||
Parameters:
|
||||
- ProwlerEcsAccount
|
||||
- ProwlerTaskRoleName
|
||||
- Label:
|
||||
default: CrossAccount Role
|
||||
Parameters:
|
||||
- ProwlerCrossAccountRole
|
||||
Parameters:
|
||||
ProwlerEcsAccount:
|
||||
Type: String
|
||||
Description: Enter AWS Account Number where Prowler ECS Task will reside.
|
||||
AllowedPattern: ^\d{12}$
|
||||
ConstraintDescription: An AWS Account Number must be a 12 digit numeric string.
|
||||
ProwlerTaskRoleName:
|
||||
Type: String
|
||||
Description: Enter Instance Role that will be given to the Prowler ECS Instance (needed to grant sts:AssumeRole rights).
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerECSTask-Role
|
||||
ProwlerCrossAccountRole:
|
||||
Type: String
|
||||
Description: Enter Name for CrossAccount Role to be created for Prowler to assess all Accounts in the AWS Organization.
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerXA-Role
|
||||
Resources:
|
||||
ProwlerRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Provides Prowler ECS tasks permissions to assess security of Accounts in AWS Organization
|
||||
RoleName: !Ref ProwlerCrossAccountRole
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
AWS:
|
||||
- !Sub arn:${AWS::Partition}:iam::${ProwlerEcsAccount}:role/${ProwlerTaskRoleName}
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
ManagedPolicyArns:
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/SecurityAudit
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/job-function/ViewOnlyAccess
|
||||
Policies:
|
||||
- PolicyName: Prowler-Additions-Policy
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowMoreReadForProwler
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- ds:ListAuthorizedApplications
|
||||
- ec2:GetEbsEncryptionByDefault
|
||||
- ecr:Describe*
|
||||
- elasticfilesystem:DescribeBackupPolicy
|
||||
- glue:GetConnections
|
||||
- glue:GetSecurityConfiguration
|
||||
- glue:SearchTables
|
||||
- lambda:GetFunction
|
||||
- s3:GetAccountPublicAccessBlock
|
||||
- shield:DescribeProtection
|
||||
- shield:GetSubscriptionState
|
||||
- ssm:GetDocument
|
||||
- support:Describe*
|
||||
- tag:GetTagKeys
|
||||
- PolicyName: Prowler-Security-Hub
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowProwlerSecurityHub
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- securityhub:BatchImportFindings
|
||||
- securityhub:GetFindings
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W11
|
||||
reason: "Prowler requires these rights to perform its Security Assessment."
|
||||
- id: W28
|
||||
reason: "Using a defined Role Name."
|
||||
Outputs:
|
||||
ProwlerCrossAccountRole:
|
||||
Description: CrossAccount Role to be used by Prowler to assess AWS Accounts in the AWS Organization.
|
||||
Value: !Ref ProwlerCrossAccountRole
|
||||
102
contrib/multi-account-securityhub/templates/CF-Prowler-ECS.yml
Normal file
@@ -0,0 +1,102 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: This Template will create the infrastructure for Prowler with ECS Fargate
|
||||
Parameters:
|
||||
ProwlerClusterName:
|
||||
Type: String
|
||||
Description: Name of the ECS Cluster that the Prowler Fargate Task will run in
|
||||
Default: ProwlerCluster
|
||||
ProwlerContainerName:
|
||||
Type: String
|
||||
Description: Name of the Prowler Container Definition within the ECS Task
|
||||
Default: prowler
|
||||
ProwlerContainerInfo:
|
||||
Type: String
|
||||
Description: ECR URI of the Prowler container
|
||||
ProwlerECSLogGroupName:
|
||||
Type: String
|
||||
Description: Name for the log group to be created
|
||||
Default: /aws/ecs/SecurityHub-Prowler
|
||||
SecurityGroupVPCId:
|
||||
Type: String
|
||||
Description: VPC Id for the Security Group to be created
|
||||
ProwlerScheduledSubnet1:
|
||||
Type: String
|
||||
Description: Subnet Id in which Prowler can be scheduled to Run
|
||||
ProwlerScheduledSubnet2:
|
||||
Type: String
|
||||
Description: A secondary Subnet Id in which Prowler can be scheduled to Run
|
||||
ECSExecutionRole:
|
||||
Type: String
|
||||
Description: ECS Execution Task Role ARN.
|
||||
ProwlerTaskRole:
|
||||
Type: String
|
||||
Description: Prowler ECS Task Role ARN.
|
||||
ECSEventRole:
|
||||
Type: String
|
||||
Description: Eventbridge Task Role ARN.
|
||||
CronExpression:
|
||||
Type: String
|
||||
Description: Cron schedule for the event rule.
|
||||
Default: cron(0 23 * * ? *)
|
||||
Resources:
|
||||
ProwlerECSCloudWatchLogsGroup:
|
||||
Type: AWS::Logs::LogGroup
|
||||
Properties:
|
||||
LogGroupName: !Ref ProwlerECSLogGroupName
|
||||
RetentionInDays: 90
|
||||
ProwlerECSCluster:
|
||||
Type: AWS::ECS::Cluster
|
||||
Properties:
|
||||
ClusterName: !Ref ProwlerClusterName
|
||||
ProwlerECSTaskDefinition:
|
||||
Type: AWS::ECS::TaskDefinition
|
||||
Properties:
|
||||
ContainerDefinitions:
|
||||
- Image: !Ref ProwlerContainerInfo
|
||||
Name: !Ref ProwlerContainerName
|
||||
LogConfiguration:
|
||||
LogDriver: awslogs
|
||||
Options:
|
||||
awslogs-group: !Ref ProwlerECSCloudWatchLogsGroup
|
||||
awslogs-region: !Ref 'AWS::Region'
|
||||
awslogs-stream-prefix: ecs
|
||||
Cpu: 1024
|
||||
ExecutionRoleArn: !Ref ECSExecutionRole
|
||||
Memory: 2048
|
||||
NetworkMode: awsvpc
|
||||
TaskRoleArn: !Ref ProwlerTaskRole
|
||||
Family: SecurityHubProwlerTask
|
||||
RequiresCompatibilities:
|
||||
- FARGATE
|
||||
ProwlerSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Properties:
|
||||
GroupDescription: Allow HTTPS Out - Prowler
|
||||
VpcId: !Ref SecurityGroupVPCId
|
||||
SecurityGroupEgress:
|
||||
- IpProtocol: tcp
|
||||
FromPort: 443
|
||||
ToPort: 443
|
||||
CidrIp: 0.0.0.0/0
|
||||
ProwlerTaskScheduler:
|
||||
Type: AWS::Events::Rule
|
||||
Properties:
|
||||
ScheduleExpression: !Ref CronExpression
|
||||
State: ENABLED
|
||||
Targets:
|
||||
- Arn: !GetAtt ProwlerECSCluster.Arn
|
||||
RoleArn: !Ref ECSEventRole
|
||||
Id: prowlerTaskScheduler
|
||||
EcsParameters:
|
||||
TaskDefinitionArn: !Ref ProwlerECSTaskDefinition
|
||||
TaskCount: 1
|
||||
LaunchType: FARGATE
|
||||
PlatformVersion: 'LATEST'
|
||||
NetworkConfiguration:
|
||||
AwsVpcConfiguration:
|
||||
AssignPublicIp: DISABLED
|
||||
SecurityGroups:
|
||||
- !Ref ProwlerSecurityGroup
|
||||
Subnets:
|
||||
- !Ref ProwlerScheduledSubnet1
|
||||
- !Ref ProwlerScheduledSubnet2
|
||||
105
contrib/multi-account-securityhub/templates/CF-Prowler-IAM.yml
Normal file
@@ -0,0 +1,105 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: This Template will create the IAM Roles needed for the Prowler infrastructure
|
||||
Parameters:
|
||||
ProwlerCrossAccountRoleName:
|
||||
Type: String
|
||||
Description: Name of the cross account Prowler IAM Role
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerXA-Role
|
||||
ECSExecutionRoleName:
|
||||
Type: String
|
||||
Description: Name for the ECS Task Execution Role
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ECSTaskExecution-Role
|
||||
ProwlerTaskRoleName:
|
||||
Type: String
|
||||
Description: Name for the ECS Prowler Task Role
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerECSTask-Role
|
||||
ECSEventRoleName:
|
||||
Type: String
|
||||
Description: Name for the Eventbridge Task Role
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerEvents-Role
|
||||
Resources:
|
||||
ECSExecutionRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Ref ECSExecutionRoleName
|
||||
ManagedPolicyArns:
|
||||
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Sid: ECSExecutionTrust
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: ecs-tasks.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
ProwlerTaskRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Ref ProwlerTaskRoleName
|
||||
Policies:
|
||||
- PolicyName: ProwlerAssumeRole
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Sid: AllowProwlerAssumeRole
|
||||
Effect: Allow
|
||||
Action: sts:AssumeRole
|
||||
Resource:
|
||||
- !Sub arn:aws:iam::*:role/${ProwlerCrossAccountRoleName}
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Sid: ECSExecutionTrust
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: ecs-tasks.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
ECSEventRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: !Ref ECSEventRoleName
|
||||
Policies:
|
||||
- PolicyName: AllowProwlerEventsECS
|
||||
PolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- ecs:RunTask
|
||||
Resource:
|
||||
- "*"
|
||||
Sid: EventRunECS
|
||||
- Effect: Allow
|
||||
Action: iam:PassRole
|
||||
Resource:
|
||||
- "*"
|
||||
Sid: EventPassRole
|
||||
Condition:
|
||||
StringLike:
|
||||
iam:PassedToService: ecs-tasks.amazonaws.com
|
||||
AssumeRolePolicyDocument:
|
||||
Version: '2012-10-17'
|
||||
Statement:
|
||||
- Sid: EventsECSExecutionTrust
|
||||
Effect: Allow
|
||||
Principal:
|
||||
Service: events.amazonaws.com
|
||||
Action: sts:AssumeRole
|
||||
Outputs:
|
||||
ECSExecutionRoleARN:
|
||||
Description: ARN of the ECS Task Execution Role
|
||||
Value: !GetAtt ECSExecutionRole.Arn
|
||||
ProwlerTaskRoleARN:
|
||||
Description: ARN of the ECS Prowler Task Role
|
||||
Value: !GetAtt ProwlerTaskRole.Arn
|
||||
ECSEventRoleARN:
|
||||
Description: ARN of the Eventbridge Task Role
|
||||
Value: !GetAtt ECSEventRole.Arn
|
||||
366
contrib/org-multi-account/ProwlerEC2.yaml
Normal file
@@ -0,0 +1,366 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create Prowler EC2 with UserData (Shell Scripts, & AWS CLI Profiles)
|
||||
|
||||
Metadata:
|
||||
AWS::CloudFormation::Interface:
|
||||
ParameterGroups:
|
||||
- Label:
|
||||
default: Prowler EC2 Instance Settings
|
||||
Parameters:
|
||||
- BuildNumber
|
||||
- ProwlerEc2Name
|
||||
- InstanceType
|
||||
- KeyPair
|
||||
- SubnetId
|
||||
- VpcId
|
||||
- Ec2Role
|
||||
- LatestAmazonLinux2AmiId
|
||||
- ProwlerCron
|
||||
- Label:
|
||||
default: S3 Settings
|
||||
Parameters:
|
||||
- ProwlerS3
|
||||
- ProwlerS3Account
|
||||
- Label:
|
||||
default: CrossAccount Role
|
||||
Parameters:
|
||||
- AwsOrgId
|
||||
- CrossAccountRole
|
||||
|
||||
Parameters:
|
||||
BuildNumber:
|
||||
Type: String
|
||||
Description: Enter Build Number (increment with Updates for cfn-init)
|
||||
AllowedPattern: ^\d*$
|
||||
ConstraintDescription: Build Number must be a numeric string.
|
||||
Default: 1
|
||||
ProwlerEc2Name:
|
||||
Type: String
|
||||
Description: Enter Name for Prowler EC2 Instance to create
|
||||
AllowedPattern: ^[\w\s_.\/=+-]{1,128}$
|
||||
ConstraintDescription: Max 128 alphanumeric characters. Also special characters supported [whitespace, _, ., /, =, +, -]
|
||||
Default: Prowler-EC2
|
||||
InstanceType:
|
||||
Description: Enter Instance Type
|
||||
Type: String
|
||||
Default: t2.micro
|
||||
KeyPair:
|
||||
Description: Choose a KeyPair
|
||||
Type: AWS::EC2::KeyPair::KeyName
|
||||
SubnetId:
|
||||
Description: Choose Subnet
|
||||
Type: AWS::EC2::Subnet::Id
|
||||
VpcId:
|
||||
Description: Choose VPC
|
||||
Type: AWS::EC2::VPC::Id
|
||||
Ec2Role:
|
||||
Description: Enter Name for EC2 Instance Role to create and attach to Prowler EC2 Instance
|
||||
Type: String
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerEC2-Role
|
||||
ProwlerCron:
|
||||
Description: Enter cron schedule. Default, runs everyday at 1am. See https://crontab.guru/, for syntax help.
|
||||
Type: String
|
||||
Default: "0 1 * * *"
|
||||
LatestAmazonLinux2AmiId:
|
||||
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
|
||||
Description: Latest AMI ID for Amazon Linux 2 (via AWS Publis SSM Parameters. See https://tinyurl.com/aws-public-ssm-parameters.
|
||||
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs
|
||||
|
||||
ProwlerS3:
|
||||
Type: String
|
||||
Description: Enter S3 Bucket for Prowler Reports. prefix-awsaccount-awsregion
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$
|
||||
ConstraintDescription: Max 63 characters. Can't start or end with dash. Can use numbers and lowercase letters.
|
||||
Default: prowler-123456789012-us-east-1
|
||||
ProwlerS3Account:
|
||||
Type: String
|
||||
Description: Enter AWS Account Number where Prowler S3 Bucket resides.
|
||||
AllowedPattern: ^\d{12}$
|
||||
ConstraintDescription: An AWS Account Number must be a 12 digit numeric string.
|
||||
Default: 123456789012
|
||||
|
||||
AwsOrgId:
|
||||
Type: String
|
||||
Description: Enter AWS Organizations ID
|
||||
AllowedPattern: ^o-[a-z0-9]{10,32}$
|
||||
ConstraintDescription: The Org Id must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters.
|
||||
Default: o-abcde12345
|
||||
CrossAccountRole:
|
||||
Type: String
|
||||
Description: Enter CrossAccount Role Prowler will be using to assess AWS Accounts in the AWS Organization. (ProwlerCrossAccountRole)
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters [+, =, ., @, -]
|
||||
Default: ProwlerXA-Role
|
||||
|
||||
Resources:
|
||||
ProwlerEc2:
|
||||
Type: AWS::EC2::Instance
|
||||
CreationPolicy:
|
||||
ResourceSignal:
|
||||
Timeout: PT5M
|
||||
Properties:
|
||||
KeyName: !Ref KeyPair
|
||||
ImageId: !Ref LatestAmazonLinux2AmiId
|
||||
IamInstanceProfile: !Ref ProwlerInstanceProfile
|
||||
InstanceType: !Ref InstanceType
|
||||
SubnetId: !Ref SubnetId
|
||||
SecurityGroupIds:
|
||||
- !Ref ProwlerSecurityGroup
|
||||
BlockDeviceMappings:
|
||||
- DeviceName: /dev/xvda
|
||||
Ebs:
|
||||
Encrypted: true
|
||||
KmsKeyId: alias/aws/ebs
|
||||
VolumeType: standard
|
||||
DeleteOnTermination: true
|
||||
VolumeSize: 8
|
||||
Tags:
|
||||
- Key: Name
|
||||
Value: !Ref ProwlerEc2Name
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
UserData:
|
||||
Fn::Base64:
|
||||
!Sub |
|
||||
#!/bin/bash
|
||||
yum update -y aws-cfn-bootstrap
|
||||
/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource ProwlerEc2 --configsets onfirstboot --region ${AWS::Region}
|
||||
yum -y update
|
||||
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ProwlerEc2 --region ${AWS::Region}
|
||||
Metadata:
|
||||
AWS::CloudFormation::Authentication:
|
||||
S3AccessCreds:
|
||||
type: S3
|
||||
buckets:
|
||||
- !Ref ProwlerS3
|
||||
roleName:
|
||||
Ref: ProwlerEc2Role
|
||||
AWS::CloudFormation::Init:
|
||||
configSets:
|
||||
onfirstboot:
|
||||
- build-number
|
||||
- configure-cfn
|
||||
- prowler-prereqs
|
||||
- prowler-reports
|
||||
- prowler-schedule
|
||||
onupdate:
|
||||
- build-number
|
||||
- prowler-prereqs
|
||||
- prowler-reports
|
||||
- prowler-schedule
|
||||
build-number:
|
||||
commands:
|
||||
show-build-number:
|
||||
command: !Sub |
|
||||
echo "BUILDNUMBER: ${BuildNumber}"
|
||||
configure-cfn:
|
||||
files:
|
||||
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
|
||||
content: !Sub |
|
||||
[cfn-auto-reloader-hook]
|
||||
triggers=post.update
|
||||
path=Resources.ProwlerEc2.Metadata.AWS::CloudFormation::Init
|
||||
action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource ProwlerEc2 --configsets onupdate --region ${AWS::Region}
|
||||
runas=root
|
||||
mode: "000400"
|
||||
owner: root
|
||||
group: root
|
||||
/etc/cfn/cfn-hup.conf:
|
||||
content: !Sub |
|
||||
[main]
|
||||
stack=${AWS::StackId}
|
||||
region=${AWS::Region}
|
||||
verbose=true
|
||||
interval=5
|
||||
mode: "000400"
|
||||
owner: root
|
||||
group: root
|
||||
services:
|
||||
sysvinit:
|
||||
cfn-hup:
|
||||
enabled: true
|
||||
ensureRunning: true
|
||||
files:
|
||||
- /etc/cfn/cfn-hup.conf
|
||||
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
|
||||
prowler-prereqs:
|
||||
files:
|
||||
/home/ec2-user/.awsvariables:
|
||||
content: !Sub |
|
||||
export S3=s3://${ProwlerS3}
|
||||
export S3ACCOUNT=${ProwlerS3Account}
|
||||
export ROLE=${CrossAccountRole}
|
||||
mode: "000600"
|
||||
owner: ec2-user
|
||||
group: ec2-user
|
||||
commands:
|
||||
01-install-prowler-prereqs-yum:
|
||||
command: |
|
||||
yum install python-pip git jq -y
|
||||
02-install-prowler-prereqs-pip:
|
||||
command: |
|
||||
sudo -u ec2-user pip install --user boto3 awscli detect-secrets
|
||||
prowler-reports:
|
||||
files:
|
||||
/home/ec2-user/run-prowler-reports.sh:
|
||||
source: !Sub https://${ProwlerS3}.s3.${AWS::Region}.amazonaws.com/run-prowler-reports.sh
|
||||
mode: "000700"
|
||||
owner: ec2-user
|
||||
group: ec2-user
|
||||
prowler-schedule:
|
||||
files:
|
||||
/home/ec2-user/mycron-prowler:
|
||||
content: !Sub |
|
||||
${ProwlerCron} bash -lc ./run-prowler-reports.sh > mycron-prowler.log
|
||||
mode: "000600"
|
||||
owner: ec2-user
|
||||
group: ec2-user
|
||||
commands:
|
||||
01-create-prowler-cron-job:
|
||||
command: |
|
||||
sudo -u ec2-user crontab /home/ec2-user/mycron-prowler
|
||||
|
||||
ProwlerSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Properties:
|
||||
GroupName: Prowler-EC2-RemoteAdministration
|
||||
GroupDescription: Allow Remote Administration
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
VpcId: !Ref VpcId
|
||||
SecurityGroupEgress:
|
||||
- Description: Allow HTTP Outbound
|
||||
IpProtocol: tcp
|
||||
FromPort: 80
|
||||
ToPort: 80
|
||||
CidrIp: 0.0.0.0/0
|
||||
- Description: Allow HTTPS Outbound
|
||||
IpProtocol: tcp
|
||||
FromPort: 443
|
||||
ToPort: 443
|
||||
CidrIp: 0.0.0.0/0
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W5
|
||||
reason: "Using http/https to Internet for updates."
|
||||
- id: W28
|
||||
reason: "Using a defined Security Group Name."
|
||||
|
||||
ProwlerInstanceProfile:
|
||||
Type: AWS::IAM::InstanceProfile
|
||||
Properties:
|
||||
Roles:
|
||||
- !Ref ProwlerEc2Role
|
||||
|
||||
ProwlerEc2Role:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Prowler EC2 Instance Role
|
||||
RoleName: !Ref Ec2Role
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service:
|
||||
- ec2.amazonaws.com
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Policies:
|
||||
- PolicyName: SSM-Agent
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowSsmAgent
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- ssm:UpdateInstanceInformation
|
||||
- ssm:ListInstanceAssociations
|
||||
- ssm:UpdateInstanceAssociationStatus
|
||||
- ssm:PutConfigurePackageResult
|
||||
- ssm:GetManifest
|
||||
- ssm:PutComplianceItems
|
||||
- ec2messages:AcknowledgeMessage
|
||||
- ec2messages:DeleteMessage
|
||||
- ec2messages:FailMessage
|
||||
- ec2messages:GetEndpoint
|
||||
- ec2messages:GetMessages
|
||||
- ec2messages:SendReply
|
||||
- PolicyName: SSM-Inventory
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowPutInventory
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- ssm:PutInventory
|
||||
- Sid: AllowGatherInventory
|
||||
Effect: Allow
|
||||
Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}::document/AWS-GatherSoftwareInventory
|
||||
Action:
|
||||
- ssm:GetDocument
|
||||
- ssm:DescribeDocument
|
||||
- PolicyName: SSM-SessionManager
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowSessionManager
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- ssmmessages:CreateControlChannel
|
||||
- ssmmessages:CreateDataChannel
|
||||
- ssmmessages:OpenControlChannel
|
||||
- ssmmessages:OpenDataChannel
|
||||
- PolicyName: Prowler-S3-Reports
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
- s3:PutObjectAcl
|
||||
- PolicyName: Prowler-CrossAccount-AssumeRole
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowStsAssumeRole
|
||||
Effect: Allow
|
||||
Resource: !Sub arn:${AWS::Partition}:iam::*:role/${CrossAccountRole}
|
||||
Action: sts:AssumeRole
|
||||
Condition:
|
||||
StringEquals:
|
||||
aws:PrincipalOrgId: !Ref AwsOrgId
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W28
|
||||
reason: "Using a defined Role Name."
|
||||
- id: W11
|
||||
reason: "Needed for SSM features."
|
||||
|
||||
Outputs:
|
||||
ProwlerEc2Account:
|
||||
Description: AWS Account Number where Prowler EC2 Instance resides.
|
||||
Value: !Ref AWS::AccountId
|
||||
ProwlerEc2Role:
|
||||
Description: Instance Role given to the Prowler EC2 Instance (needed to grant sts:AssumeRole rights).
|
||||
Value: !Ref ProwlerEc2Role
|
||||
ProwlerS3:
|
||||
Description: S3 Bucket for Prowler Reports
|
||||
Value: !Ref ProwlerS3
|
||||
116
contrib/org-multi-account/ProwlerRole.yaml
Normal file
@@ -0,0 +1,116 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create the Cross-Account IAM Prowler Role
|
||||
|
||||
Metadata:
|
||||
AWS::CloudFormation::Interface:
|
||||
ParameterGroups:
|
||||
- Label:
|
||||
default: EC2 Settings
|
||||
Parameters:
|
||||
- ProwlerEc2Account
|
||||
- ProwlerEc2Role
|
||||
- Label:
|
||||
default: S3 Settings
|
||||
Parameters:
|
||||
- ProwlerS3
|
||||
- Label:
|
||||
default: CrossAccount Role
|
||||
Parameters:
|
||||
- ProwlerCrossAccountRole
|
||||
|
||||
Parameters:
|
||||
ProwlerS3:
|
||||
Type: String
|
||||
Description: Enter S3 Bucket for Prowler Reports. prefix-awsaccount-awsregion
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$
|
||||
Default: prowler-123456789012-us-east-1
|
||||
ProwlerEc2Account:
|
||||
Type: String
|
||||
Description: Enter AWS Account Number where Prowler EC2 Instance will reside.
|
||||
AllowedPattern: ^\d{12}$
|
||||
ConstraintDescription: An AWS Account Number must be a 12 digit numeric string.
|
||||
ProwlerEc2Role:
|
||||
Type: String
|
||||
Description: Enter Instance Role that will be given to the Prowler EC2 Instance (needed to grant sts:AssumeRole rights).
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerEC2-Role
|
||||
ProwlerCrossAccountRole:
|
||||
Type: String
|
||||
Description: Enter Name for CrossAccount Role to be created for Prowler to assess all Accounts in the AWS Organization.
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerXA-Role
|
||||
|
||||
Resources:
|
||||
ProwlerRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Provides Prowler EC2 instance permissions to assess security of Accounts in AWS Organization
|
||||
RoleName: !Ref ProwlerCrossAccountRole
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
AWS:
|
||||
- !Sub arn:${AWS::Partition}:iam::${ProwlerEc2Account}:root
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Condition:
|
||||
StringLike:
|
||||
aws:PrincipalArn: !Sub arn:${AWS::Partition}:iam::${ProwlerEc2Account}:role/${ProwlerEc2Role}
|
||||
ManagedPolicyArns:
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/SecurityAudit
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/job-function/ViewOnlyAccess
|
||||
Policies:
|
||||
- PolicyName: Prowler-Additions-Policy
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowMoreReadForProwler
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- ds:ListAuthorizedApplications
|
||||
- ec2:GetEbsEncryptionByDefault
|
||||
- ecr:Describe*
|
||||
- elasticfilesystem:DescribeBackupPolicy
|
||||
- glue:GetConnections
|
||||
- glue:GetSecurityConfiguration
|
||||
- glue:SearchTables
|
||||
- lambda:GetFunction
|
||||
- s3:GetAccountPublicAccessBlock
|
||||
- shield:DescribeProtection
|
||||
- shield:GetSubscriptionState
|
||||
- ssm:GetDocument
|
||||
- support:Describe*
|
||||
- tag:GetTagKeys
|
||||
- PolicyName: Prowler-S3-Reports
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W11
|
||||
reason: "Prowler requires these rights to perform its Security Assessment."
|
||||
- id: W28
|
||||
reason: "Using a defined Role Name."
|
||||
|
||||
Outputs:
|
||||
ProwlerCrossAccountRole:
|
||||
Description: CrossAccount Role to be used by Prowler to assess AWS Accounts in the AWS Organization.
|
||||
Value: !Ref ProwlerCrossAccountRole
|
||||
106
contrib/org-multi-account/ProwlerS3.yaml
Normal file
@@ -0,0 +1,106 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create Prowler S3 Bucket for Prowler Reports
|
||||
|
||||
Parameters:
|
||||
AwsOrgId:
|
||||
Type: String
|
||||
Description: >
|
||||
Enter AWS Organizations ID.
|
||||
This is used to restrict permissions to least privilege.
|
||||
AllowedPattern: ^o-[a-z0-9]{10,32}$
|
||||
ConstraintDescription: The Org Id must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters.
|
||||
Default: o-abcde12345
|
||||
S3Prefix:
|
||||
Type: String
|
||||
Description: >
|
||||
Enter S3 Bucket Name Prefix (in lowercase).
|
||||
Bucket will be named: prefix-awsaccount-awsregion (i.e., prowler-123456789012-us-east-1)
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,33}[a-z0-9]$
|
||||
ConstraintDescription: >
|
||||
Max 35 characters, as "-awsaccount-awsregion" will be added, and max name is 63 characters.
|
||||
Can't start or end with dash. Can use numbers and lowercase letters.
|
||||
Default: prowler
|
||||
|
||||
Resources:
|
||||
ProwlerS3:
|
||||
Type: AWS::S3::Bucket
|
||||
Properties:
|
||||
BucketName: !Sub ${S3Prefix}-${AWS::AccountId}-${AWS::Region}
|
||||
BucketEncryption:
|
||||
ServerSideEncryptionConfiguration:
|
||||
- ServerSideEncryptionByDefault:
|
||||
SSEAlgorithm: "AES256"
|
||||
AccessControl: Private
|
||||
PublicAccessBlockConfiguration:
|
||||
BlockPublicAcls: True
|
||||
BlockPublicPolicy: True
|
||||
IgnorePublicAcls: True
|
||||
RestrictPublicBuckets: True
|
||||
VersioningConfiguration:
|
||||
Status: Enabled
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W35
|
||||
reason: "This S3 Bucket is only being used by the AWS Organization to download/upload prowler reports."
|
||||
|
||||
ProwlerS3BucketPolicy:
|
||||
Type: AWS::S3::BucketPolicy
|
||||
Properties:
|
||||
Bucket: !Ref ProwlerS3
|
||||
PolicyDocument:
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Principal: "*"
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
- s3:PutObjectAcl
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Condition:
|
||||
StringEquals:
|
||||
aws:PrincipalOrgId: !Ref AwsOrgId
|
||||
- Sid: DenyNonSSLRequests
|
||||
Effect: Deny
|
||||
Action: s3:*
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Principal: "*"
|
||||
Condition:
|
||||
Bool:
|
||||
aws:SecureTransport: false
|
||||
- Sid: DenyIncorrectEncryptionHeader
|
||||
Effect: Deny
|
||||
Principal: "*"
|
||||
Action: s3:PutObject
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
# Allow uploads with No Encryption, as S3 Default Encryption still applies.
|
||||
# If Encryption is set, only allow uploads with AES256.
|
||||
Condition:
|
||||
"Null":
|
||||
s3:x-amz-server-side-encryption: false
|
||||
StringNotEquals:
|
||||
s3:x-amz-server-side-encryption: AES256
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: F16
|
||||
reason: "This S3 Bucket Policy has a condition that only allows access to the AWS Organization."
|
||||
|
||||
|
||||
Outputs:
|
||||
ProwlerS3:
|
||||
Description: S3 Bucket for Prowler Reports
|
||||
Value: !Ref ProwlerS3
|
||||
ProwlerS3Account:
|
||||
Description: AWS Account Number where Prowler S3 Bucket resides.
|
||||
Value: !Ref AWS::AccountId
|
||||
151
contrib/org-multi-account/README.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Example Solution: Organizational Prowler Deployment
|
||||
|
||||
Deploys [Prowler](https://github.com/prowler-cloud/prowler) to assess all Accounts in an AWS Organization on a schedule, creates assessment reports in HTML, and stores them in an S3 bucket.
|
||||
|
||||
---
|
||||
|
||||
## Example Solution Goals
|
||||
|
||||
- Using minimal technologies, so solution can be more easily adopted, and further enhanced as needed.
|
||||
- [Amazon EC2](https://aws.amazon.com/ec2/), to run Prowler
|
||||
- [Amazon S3](https://aws.amazon.com/s3/), to store Prowler script & reports.
|
||||
- [AWS CloudFormation](https://aws.amazon.com/cloudformation/), to provision the AWS resources.
|
||||
- [AWS Systems Manager Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html), Optional, but recommended, to manage the Prowler EC2 instance, without having to allow inbound ssh.
|
||||
- Staying cohesive with Prowler, for scripting, only leveraging:
|
||||
- Bash Shell
|
||||
- AWS CLI
|
||||
- Adhering to the principle of least privilege.
|
||||
- Supporting an AWS Multi-Account approach
|
||||
- Runs Prowler against All accounts in the AWS Organization
|
||||
- ***NOTE: If using this solution, you are responsible for making your own independent assessment of the solution and ensuring it complies with your company security and operational standards.***
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
1. [ProwlerS3.yaml](ProwlerS3.yaml)
|
||||
- Creates Private S3 Bucket for Prowler script and reports.
|
||||
- Enables [Amazon S3 Block Public Access](https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html)
|
||||
- Enables SSE-S3 with [Amazon S3 Default Encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html)
|
||||
- Versioning Enabled
|
||||
- Bucket Policy limits API actions to Principals from the same AWS Organization.
|
||||
1. [ProwlerRole.yaml](ProwlerRole.yaml)
|
||||
- Creates Cross-Account Role for Prowler to assess accounts in AWS Organization
|
||||
- Allows Role to be assumed by the Prowler EC2 instance role in the AWS account where Prowler EC2 resides (preferably the Audit/Security account).
|
||||
- Role has [permissions](https://github.com/prowler-cloud/prowler#custom-iam-policy) needed for Prowler to assess accounts.
|
||||
- Role has rights to Prowler S3 from Component #1.
|
||||
1. [ProwlerEC2.yaml](ProwlerEC2.yaml)
|
||||
- Creates Prowler EC2 instance
|
||||
- Uses the Latest Amazon Linux 2 AMI
|
||||
- Uses ```t2.micro``` Instance Type
|
||||
- Encrypts Root Volume with AWS Managed Key "aws/ebs"
|
||||
- Uses [cfn-init](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-init.html) for prepping the Prowler EC2
|
||||
- Installs necessary [packages](https://github.com/prowler-cloud/prowler#requirements-and-installation) for Prowler
|
||||
- Downloads [run-prowler-reports.sh](src/run-prowler-reports.sh) script from Prowler S3 from Component #1.
|
||||
- Creates ```/home/ec2-user/.awsvariables```, to store CloudFormation data as variables to be used in script.
|
||||
- Creates cron job for Prowler to run on a schedule.
|
||||
- Creates Prowler Security Group
|
||||
- Denies inbound access. If using ssh to manage Prowler, then update Security Group with pertinent rule.
|
||||
- Allows outbound 80/443 for updates, and Amazon S3 communications -
|
||||
- Creates Instance Role that is used for Prowler EC2
|
||||
- Role has permissions for [Systems Manager Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) communications, and [Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)
|
||||
- Role has rights to Prowler S3 from Component #1.
|
||||
- Role has rights to Assume Cross-Account Role from Component #2.
|
||||
1. [run-prowler-reports.sh](src/run-prowler-reports.sh)
|
||||
- Script is documented accordingly.
|
||||
- Script 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 cislevel1: used to specify cislevel1 checks for Prowler to assess
|
||||
|
||||
```bash
|
||||
./prowler/prowler -R "$ROLE" -A "$accountId" -g cislevel1 -M html
|
||||
```
|
||||
|
||||
- NOTE: Script can be modified to run Prowler as desired.
|
||||
- Script runs Prowler against 1 AWS Account at a time.
|
||||
- Update PARALLEL_ACCOUNTS variable in script, to specify how many Accounts to assess with Prowler in parallel.
|
||||
- If running against multiple AWS Accounts in parallel, monitor performance, and upgrade Instance Type as necessary.
|
||||
|
||||
```bash
|
||||
PARALLEL_ACCOUNTS="1"
|
||||
```
|
||||
|
||||
- In summary:
|
||||
- Download latest version of [Prowler](https://github.com/prowler-cloud/prowler)
|
||||
- Find AWS Master Account
|
||||
- Lookup All Accounts in AWS Organization
|
||||
- Run Prowler against All Accounts in AWS Organization
|
||||
- Save Reports to reports prefix in S3 from Component #1
|
||||
- Report Names: date+time-accountid-report.html
|
||||
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Deploy [ProwlerS3.yaml](ProwlerS3.yaml) in the Logging Account.
|
||||
- Could be deployed to any account in the AWS Organizations, if desired.
|
||||
- See [How to get AWS Organization ID](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_org_details.html#orgs_view_org)
|
||||
- Take Note of CloudFormation Outputs, that will be needed in deploying the below CloudFormation templates.
|
||||
1. Upload [run-prowler-reports.sh](src/run-prowler-reports.sh) to the root of the S3 Bucket created in Step #1.
|
||||
1. Deploy [ProwlerRole.yaml](ProwlerRole.yaml) in the Master Account
|
||||
- Use CloudFormation Stacks, to deploy to Master Account, as organizational StackSets don't apply to the Master Account.
|
||||
- Use CloudFormation StackSet, to deploy to all Member Accounts. See [Create Stack Set with Service-Managed Permissions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-getting-started-create.html#stacksets-orgs-associate-stackset-with-org)
|
||||
- Take Note of CloudFormation Outputs, that will be needed in deploying the below CloudFormation templates.
|
||||
1. Deploy [ProwlerEC2.yaml](ProwlerEC2.yaml) in the Audit/Security Account
|
||||
- Could be deployed to any account in the AWS Organizations, if desired.
|
||||
1. Prowler will run against all Accounts in AWS Organization, per the schedule you provided, and set in a cron job for ```ec2-user```
|
||||
|
||||
---
|
||||
|
||||
## Post-Setup
|
||||
|
||||
### Run Prowler on a Schedule against all Accounts in AWS Organization
|
||||
|
||||
1. Prowler will run on the Schedule you provided.
|
||||
1. Cron job for ```ec2-user``` is managing the schedule.
|
||||
1. This solution implemented this automatically. Nothing for you to do.
|
||||
|
||||
### Ad hoc Run Prowler against all Accounts in AWS Organization
|
||||
|
||||
1. Connect to Prowler EC2 Instance
|
||||
- If using Session Manager, then after login, switch to ```ec2-user```, via: ```sudo bash``` and ```su - ec2-user```
|
||||
- If using SSH, then login as ```ec2-user```
|
||||
1. Run Prowler Script
|
||||
|
||||
```bash
|
||||
cd /home/ec2-user
|
||||
./run-prowler-reports.sh
|
||||
```
|
||||
|
||||
### Ad hoc Run Prowler Interactively
|
||||
|
||||
1. Connect to Prowler EC2 Instance
|
||||
- If using Session Manager, then after login, switch to ```ec2-user```, via: ```sudo bash``` and ```su - ec2-user```
|
||||
- If using SSH, then login as ```ec2-user```
|
||||
1. See Cross-Account Role and S3 Bucket being used for Prowler
|
||||
|
||||
```bash
|
||||
cd /home/ec2-user
|
||||
cat .awsvariables
|
||||
```
|
||||
|
||||
1. Run Prowler interactively. See [Usage Examples](https://github.com/prowler-cloud/prowler#usage)
|
||||
|
||||
```bash
|
||||
cd /home/ec2-user
|
||||
./prowler/prowler
|
||||
```
|
||||
|
||||
### Upgrading Prowler to Latest Version
|
||||
|
||||
1. Connect to Prowler EC2 Instance
|
||||
- If using Session Manager, then after login, switch to ```ec2-user```, via: ```sudo bash``` and ```su - ec2-user```
|
||||
- If using SSH, then login as ```ec2-user```
|
||||
1. Delete the existing version of Prowler, and download the latest version of Prowler
|
||||
|
||||
```bash
|
||||
cd /home/ec2-user
|
||||
rm -rf prowler
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
```
|
||||
48
contrib/org-multi-account/serverless_codebuild/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Organizational Prowler with Serverless
|
||||
|
||||
Langage: [Korean](README_kr.md)
|
||||
|
||||
This project is created to apply prowler in a multi-account environment within AWS Organizations.
|
||||
CloudWatch triggers CodeBuild every fixed time.
|
||||
CodeBuild executes the script which clones the latest prowler from [here](https://github.com/prowler-cloud/prowler) and performs security assessment on all the accounts in AWS Organizations. The assessment reports are sent to S3 bucket in Log Archive Account.
|
||||
|
||||
For more information on how to use prowler, see [here](https://github.com/prowler-cloud/prowler#usage).
|
||||
|
||||

|
||||
|
||||
1. **Log Archive Account**
|
||||
1. Deploy [ProwlerS3.yaml](templates/ProwlerS3.yaml) in CloudFormation console.
|
||||
The template creates S3 bucket for reports and bucket policy that limits API actions to principals from its AWS Organizations.
|
||||
- AwsOrgId : AWS Organizations' Organization ID
|
||||
- S3Prefix : The prefix included in the bucket name
|
||||
2. **Master Account**
|
||||
1. Deploy [ProwlerRole.yaml](templates/ProwlerRole.yaml) stack to CloudFormation in a bid to create resources to master account itself.
|
||||
(The template will be also deployed for other member accounts as a StackSet)
|
||||
- ProwlerCodeBuildAccount : Audit Acccount ID where CodeBuild resides. (preferably Audit/Security account)
|
||||
- ProwlerCodeBuildRole : Role name to use in CodeBuild service
|
||||
- ProwlerCrossAccountRole : Role name to assume for Cross account
|
||||
- ProwlerS3 : The S3 bucket name where reports will be put
|
||||
1. Create **StackSet** with [ProwlerRole.yaml](templates/ProwlerRole.yaml) to deploy Role into member accounts in AWS Organizations.
|
||||
- ProwlerCodeBuildAccount : Audit Acccount ID where CodeBuild resides. (preferably Audit/Security account)
|
||||
- ProwlerCodeBuildRole : Role name to use in CodeBuild service
|
||||
- ProwlerCrossAccountRole : Role name to assume for Cross account
|
||||
- ProwlerS3 : The S3 bucket name where reports will be put
|
||||
- Permission : Service-managed permissions
|
||||
- Deploy target : Deploy to organization 선택, Enable, Delete stacks 선택
|
||||
- Specify regions : Region to deploy
|
||||
3. **Audit Account**
|
||||
1. Go to S3 console, create a bucket, upload [run-prowler-reports.sh.zip](src/run-prowler-reports.sh.zip)
|
||||
- bucket name : prowler-util-*[Account ID]*-*[region]*
|
||||

|
||||
|
||||
1. Deploy [ProwlerCodeBuildStack.yaml](templates/ProwlerCodeBuildStack.yaml) which creates CloudWatch Rule to trigger CodeBuild every fixed time, allowing prowler to audit multi-accounts.
|
||||
- AwsOrgId : AWS Organizations' Organization ID
|
||||
- CodeBuildRole : Role name to use in CodeBuild service
|
||||
- CodeBuildSourceS3 : Object location uploaded from i
|
||||
- prowler-util-*[Account ID]*-*[region]/**run-prowler-reports.sh.zip**
|
||||
- CrossAccountRole : Role name for cross account created in the process **2** above.
|
||||
- ProwlerReportS3 : The S3 bucket name where reports will be put
|
||||
- ProwlerReportS3Account : The account where the report S3 bucket resides.
|
||||
1. If you'd like to change the scheduled time,
|
||||
1. You can change the cron expression of ScheduleExpression within [ProwlerCodeBuildStack.yaml](templates/ProwlerCodeBuildStack.yaml).
|
||||
2. Alternatively, you can make changes directrly from Events > Rules > ProwlerExecuteRule > Actions > Edit in CloudWatch console.
|
||||
62
contrib/org-multi-account/serverless_codebuild/README_kr.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Organizational Prowler with Serverless
|
||||
|
||||
Langage: [English](README.md)
|
||||
|
||||
이 문서는 AWS Organization 내의 multi account 환경에서 prowler 를 적용하기 위해 작성된 문서입니다.
|
||||
일정 시간마다 CloudWatch는 CodeBuild 를 트리거합니다.
|
||||
CodeBuild 는 최신의 [prowler](https://github.com/prowler-cloud/prowler) 소스를 클론받고,
|
||||
Organization 내의 모든 Account 에 대해 security assessment 를 수행합니다.
|
||||
prowler 의 자세한 사용방법은 [이 곳](https://github.com/prowler-cloud/prowler#usagee) 을 참고합니다.
|
||||
|
||||

|
||||
|
||||
1. **Log Archive Account**에 접속합니다.
|
||||
1. 아래 템플릿을 CloudFormation console 에서 배포합니다. 이를 통해 prowler 의 security assessment report 가 저장되는 bucket 과 bucket policy 를 생성합니다.
|
||||
|
||||
[ProwlerS3.yaml](templates/ProwlerS3.yaml)
|
||||
|
||||
- AwsOrgId : AWS Organizations의 Organization ID
|
||||
- S3Prefix : 생성될 버킷의 이름에 포함되는 prefix
|
||||
2. **Master Account** 에 접속합니다.
|
||||
1. 아래 템플릿을 이용하여 CloudFormation **Stack**을 생성합니다. StackSet은 Master account 에 적용되지 않으므로 Stack 으로도 배포가 필요합니다.
|
||||
|
||||
[ProwlerRole.yaml](templates/ProwlerRole.yaml)
|
||||
|
||||
- ProwlerCodeBuildAccount : CodeBuild 가 있는 Audit Acccount ID
|
||||
- ProwlerCodeBuildRole : CodeBuild의 생성될 Role 이름
|
||||
- ProwlerCrossAccountRole : Cross account 용 Assume할 Role 이름
|
||||
- ProwlerS3 : report 가 저장될 S3 bucket 명
|
||||
2. 아래 템플릿을 이용하여 CloudFormation **StackSet**을 생성하여, Organazation에 포함된 account 대상으로도 아래 템플릿을 배포합니다.
|
||||
|
||||
[ProwlerRole.yaml](templates/ProwlerRole.yaml)
|
||||
|
||||
- ProwlerCodeBuildAccount : CodeBuild 가 있는 Audit Acccount
|
||||
- ProwlerCodeBuildRole : CodeBuild에서 사용할 Role 이름
|
||||
- ProwlerCrossAccountRole : Cross account 용 Assume할 Role 이름
|
||||
- ProwlerS3 : report 가 저장될 S3 bucket 명
|
||||
- Permission : Service-managed permissions
|
||||
- Deploy target : Deploy to organization 선택, Enable, Delete stacks 선택
|
||||
- Specify regions : 배포할 대상 리전을 선택
|
||||
3. **Audit Account**에 접속합니다.
|
||||
1. **S3 console** 로 이동하여 버킷을 생성하고 아래 항목을 **업로드**한 후, 버킷명을 복사해둡니다.
|
||||
|
||||
[run-prowler-reports.sh.zip](src/run-prowler-reports.sh.zip)
|
||||
|
||||
- bucket name : prowler-util-*<Account ID>*-*<region>*
|
||||
|
||||

|
||||
|
||||
2. 아래 템플릿으로 **CloudFormation stack** 을 생성합니다. 이 템플릿은 CloudWatch Rule 을 생성하여 일정 시간마다 CodeBuild 를 실행하여 prowler 가 multi accounts 를 audit 할 수 있도록 합니다.
|
||||
|
||||
[ProwlerCodeBuildStack.yaml](templates/ProwlerCodeBuildStack.yaml)
|
||||
|
||||
- AwsOrgId : AWS Organizations의 Organization ID
|
||||
- CodeBuildRole : CodeBuild의 서비스 Role 이름
|
||||
- CodeBuildSourceS3 : a 에서 업로드한 object 위치
|
||||
- prowler-util-*<Account ID>*-*<region>/***run-prowler-reports.sh.zip**
|
||||
- CrossAccountRole : 2번에서 생성한 Cross Account 용 Role 이름
|
||||
- ProwlerReportS3 : report 가 저장될 S3 bucket 명
|
||||
- ProwlerReportS3Account : report 가 저장될 S3 bucket이 위치한 Account
|
||||
3. 스케줄 된 시간을 변경하고 싶은 경우
|
||||
1. [ProwlerCodeBuildStack.yaml](templates/ProwlerCodeBuildStack.yaml) 내에서 ScheduleExpression의 크론 표현식을 변경할 수 있습니다.
|
||||
2. 또는 CloudWatch console 에서 Events > Rules > ProwlerExecuteRule > Actions > Edit 에서 직접 변경할 수 있습니다.
|
||||
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Run Prowler against All AWS Accounts in an AWS Organization
|
||||
|
||||
# Change Directory (rest of the script, assumes your in the ec2-user home directory)
|
||||
# cd /home/ec2-user || exit
|
||||
|
||||
# Show Prowler Version, and Download Prowler, if it doesn't already exist
|
||||
if ! ./prowler/prowler -V 2>/dev/null; then
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
./prowler/prowler -V
|
||||
fi
|
||||
|
||||
# Source .awsvariables (to read in Environment Variables from CloudFormation Data)
|
||||
# shellcheck disable=SC1091
|
||||
# source .awsvariables
|
||||
|
||||
# Get Values from Environment Variables Created on EC2 Instance from CloudFormation Data
|
||||
echo "S3: $S3"
|
||||
echo "S3ACCOUNT: $S3ACCOUNT"
|
||||
echo "ROLE: $ROLE"
|
||||
echo "FORMAT: $FORMAT"
|
||||
|
||||
# CleanUp Last Ran Prowler Reports, as they are already stored in S3.
|
||||
rm -rf prowler/output/*.html
|
||||
|
||||
# Function to unset AWS Profile Variables
|
||||
unset_aws() {
|
||||
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
unset_aws
|
||||
|
||||
# Find THIS Account AWS Number
|
||||
CALLER_ARN=$(aws sts get-caller-identity --output text --query "Arn")
|
||||
PARTITION=$(echo "$CALLER_ARN" | cut -d: -f2)
|
||||
THISACCOUNT=$(echo "$CALLER_ARN" | cut -d: -f5)
|
||||
echo "THISACCOUNT: $THISACCOUNT"
|
||||
echo "PARTITION: $PARTITION"
|
||||
|
||||
# Function to Assume Role to THIS Account & Create Session
|
||||
this_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$THISACCOUNT":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
echo "this_account_session done..."
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Find AWS Master Account
|
||||
this_account_session
|
||||
AWSMASTER=$(aws organizations describe-organization --query Organization.MasterAccountId --output text)
|
||||
echo "AWSMASTER: $AWSMASTER"
|
||||
|
||||
# Function to Assume Role to Master Account & Create Session
|
||||
master_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$AWSMASTER":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
echo "master_account_session done..."
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Lookup All Accounts in AWS Organization
|
||||
master_account_session
|
||||
ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[*].Id --output text)
|
||||
|
||||
# Function to Assume Role to S3 Account & Create Session
|
||||
s3_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$S3ACCOUNT":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
echo "s3_account_session done..."
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Run Prowler against Accounts in AWS Organization
|
||||
echo "AWS Accounts in Organization"
|
||||
echo "$ACCOUNTS_IN_ORGS"
|
||||
PARALLEL_ACCOUNTS="1"
|
||||
for accountId in $ACCOUNTS_IN_ORGS; do
|
||||
# shellcheck disable=SC2015
|
||||
test "$(jobs | wc -l)" -ge $PARALLEL_ACCOUNTS && wait || true
|
||||
{
|
||||
START_TIME=$SECONDS
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
# Run Prowler
|
||||
echo -e "Assessing AWS Account: $accountId, using Role: $ROLE on $(date)"
|
||||
# remove -g cislevel for a full report and add other formats if needed
|
||||
./prowler/prowler -R "$ROLE" -A "$accountId" -g cislevel1 -M $FORMAT -z
|
||||
echo "Report stored locally at: prowler/output/ directory"
|
||||
TOTAL_SEC=$((SECONDS - START_TIME))
|
||||
echo -e "Completed AWS Account: $accountId, using Role: $ROLE on $(date)"
|
||||
printf "Completed AWS Account: $accountId in %02dh:%02dm:%02ds" $((TOTAL_SEC / 3600)) $((TOTAL_SEC % 3600 / 60)) $((TOTAL_SEC % 60))
|
||||
echo ""
|
||||
} &
|
||||
done
|
||||
|
||||
# Wait for All Prowler Processes to finish
|
||||
wait
|
||||
echo "Prowler Assessments Completed against All Accounts in the AWS Organization. Starting S3 copy operations..."
|
||||
|
||||
# Upload Prowler Report to S3
|
||||
s3_account_session
|
||||
aws s3 cp prowler/output/ "$S3/reports/" --recursive --include "*.html" --acl bucket-owner-full-control
|
||||
echo "Assessment reports successfully copied to S3 bucket"
|
||||
|
||||
# Final Wait for All Prowler Processes to finish
|
||||
wait
|
||||
echo "Prowler Assessments Completed"
|
||||
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Creates a CodeBuild project to audit an AWS account with Prowler and stores the html report in a S3 bucket.
|
||||
Parameters:
|
||||
AwsOrgId:
|
||||
Type: String
|
||||
Description: Enter AWS Organizations ID
|
||||
AllowedPattern: ^o-[a-z0-9]{10,32}$
|
||||
ConstraintDescription: The Org Id must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters.
|
||||
Default: o-itdezkbz6h
|
||||
CodeBuildRole:
|
||||
Description: Enter Name for CodeBuild Role to create
|
||||
Type: String
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerCodeBuild-Role
|
||||
CodeBuildSourceS3:
|
||||
Type: String
|
||||
Description: Enter like <bucket-name>/<path>/<object-name>.zip
|
||||
ConstraintDescription: Max 63 characters. Can't start or end with dash. Can use numbers and lowercase letters.
|
||||
Default: prowler-util-411267690458-ap-northeast-2/run-prowler-reports.sh.zip
|
||||
ProwlerReportS3:
|
||||
Type: String
|
||||
Description: Enter S3 Bucket for Prowler Reports. prefix-awsaccount-awsregion
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$
|
||||
ConstraintDescription: Max 63 characters. Can't start or end with dash. Can use numbers and lowercase letters.
|
||||
Default: prowler-954896828174-ap-northeast-2
|
||||
ProwlerReportS3Account:
|
||||
Type: String
|
||||
Description: Enter AWS Account Number where Prowler S3 Bucket resides.
|
||||
AllowedPattern: ^\d{12}$
|
||||
ConstraintDescription: An AWS Account Number must be a 12 digit numeric string.
|
||||
Default: 954896828174
|
||||
CrossAccountRole:
|
||||
Type: String
|
||||
Description: Enter CrossAccount Role Prowler will be using to assess AWS Accounts in the AWS Organization. (ProwlerCrossAccountRole)
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters [+, =, ., @, -]
|
||||
Default: ProwlerXA-CBRole
|
||||
ProwlerReportFormat:
|
||||
Type: String
|
||||
Description: Enter Prowler Option like html, csv, json
|
||||
Default: html
|
||||
|
||||
Resources:
|
||||
ProwlerCodeBuildRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Prowler CodeBuild Role
|
||||
RoleName: !Ref CodeBuildRole
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service:
|
||||
- codebuild.amazonaws.com
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Policies:
|
||||
- PolicyName: Prowler-S3
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerReportS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerReportS3}/*
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
- s3:PutObjectAcl
|
||||
- Sid: AllowReadOnlyS3Access
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- "s3:Get*"
|
||||
- "s3:List*"
|
||||
- PolicyName: Prowler-CrossAccount-AssumeRole
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowStsAssumeRole
|
||||
Effect: Allow
|
||||
Resource: !Sub arn:${AWS::Partition}:iam::*:role/${CrossAccountRole}
|
||||
Action: sts:AssumeRole
|
||||
Condition:
|
||||
StringEquals:
|
||||
aws:PrincipalOrgId: !Ref AwsOrgId
|
||||
- PolicyName: Prowler-CloudWatch
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowCreateLogs
|
||||
Effect: Allow
|
||||
Resource: !Sub arn:${AWS::Partition}:logs:*:*:log-group:*
|
||||
Action:
|
||||
- logs:CreateLogGroup
|
||||
- logs:CreateLogStream
|
||||
- Sid: AllowPutevent
|
||||
Effect: Allow
|
||||
Resource: !Sub arn:${AWS::Partition}:logs:*:*:log-group:*:log-stream:*
|
||||
Action:
|
||||
- logs:PutLogEvents
|
||||
|
||||
ProwlerCodeBuild:
|
||||
Type: AWS::CodeBuild::Project
|
||||
Properties:
|
||||
Artifacts:
|
||||
Type: NO_ARTIFACTS
|
||||
Source:
|
||||
Type: S3
|
||||
Location: !Ref CodeBuildSourceS3
|
||||
BuildSpec: |
|
||||
version: 0.2
|
||||
phases:
|
||||
install:
|
||||
runtime-versions:
|
||||
python: 3.8
|
||||
commands:
|
||||
- echo "Updating yum ..."
|
||||
- yum -y update --skip-broken
|
||||
- echo "Updating pip ..."
|
||||
- python -m pip install --upgrade pip
|
||||
- echo "Installing requirements ..."
|
||||
- pip install "git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets"
|
||||
build:
|
||||
commands:
|
||||
- echo "Running Prowler with script"
|
||||
- chmod +x run-prowler-reports.sh
|
||||
- ./run-prowler-reports.sh
|
||||
post_build:
|
||||
commands:
|
||||
- echo "Done!"
|
||||
Environment:
|
||||
# AWS CodeBuild free tier includes 100 build minutes of BUILD_GENERAL1_SMALL per month.
|
||||
# BUILD_GENERAL1_SMALL: Use up to 3 GB memory and 2 vCPUs for builds. $0.005/minute.
|
||||
# BUILD_GENERAL1_MEDIUM: Use up to 7 GB memory and 4 vCPUs for builds. $0.01/minute.
|
||||
# BUILD_GENERAL1_LARGE: Use up to 15 GB memory and 8 vCPUs for builds. $0.02/minute.
|
||||
# BUILD_GENERAL1_2XLARGE: Use up to 144 GB memory and 72 vCPUs for builds. $0.20/minute.
|
||||
ComputeType: "BUILD_GENERAL1_SMALL"
|
||||
Image: "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
|
||||
Type: "LINUX_CONTAINER"
|
||||
EnvironmentVariables:
|
||||
- Name: "S3"
|
||||
Value: !Sub s3://${ProwlerReportS3}
|
||||
Type: PLAINTEXT
|
||||
- Name: "S3ACCOUNT"
|
||||
Value: !Ref ProwlerReportS3Account
|
||||
Type: PLAINTEXT
|
||||
- Name: "ROLE"
|
||||
Value: !Ref CrossAccountRole
|
||||
Type: PLAINTEXT
|
||||
- Name: "FORMAT"
|
||||
Value: !Ref ProwlerReportFormat
|
||||
Type: PLAINTEXT
|
||||
Description: Run Prowler assessment
|
||||
ServiceRole: !GetAtt ProwlerCodeBuildRole.Arn
|
||||
TimeoutInMinutes: 300
|
||||
|
||||
ProwlerCWRuleRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service:
|
||||
- events.amazonaws.com
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Description: ProwlerCWRuleRole
|
||||
RoleName: ProwlerCWRule-Role
|
||||
Policies:
|
||||
- PolicyName: Rule-Events
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AWSEventInvokeCodeBuild
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- codebuild:StartBuild
|
||||
|
||||
ProwlerRule:
|
||||
Type: AWS::Events::Rule
|
||||
Properties:
|
||||
Description: This rule will trigger CodeBuild to audit AWS Accounts in my Organization with Prowler
|
||||
ScheduleExpression: cron(0 21 * * ? *)
|
||||
RoleArn: !GetAtt ProwlerCWRuleRole.Arn
|
||||
Name: ProwlerExecuteRule
|
||||
State: ENABLED
|
||||
Targets:
|
||||
- Arn: !Sub ${ProwlerCodeBuild.Arn}
|
||||
Id: Prowler-CodeBuild-Target
|
||||
RoleArn: !GetAtt ProwlerCWRuleRole.Arn
|
||||
|
||||
|
||||
Outputs:
|
||||
ProwlerEc2Account:
|
||||
Description: AWS Account Number where Prowler EC2 Instance resides.
|
||||
Value: !Ref AWS::AccountId
|
||||
ProwlerCodeBuildRole:
|
||||
Description: Instance Role given to the Prowler EC2 Instance (needed to grant sts:AssumeRole rights).
|
||||
Value: !Ref ProwlerCodeBuildRole
|
||||
ProwlerReportS3:
|
||||
Description: S3 Bucket for Prowler Reports
|
||||
Value: !Ref ProwlerReportS3
|
||||
@@ -0,0 +1,127 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create the Cross-Account IAM Prowler Role
|
||||
|
||||
Metadata:
|
||||
AWS::CloudFormation::Interface:
|
||||
ParameterGroups:
|
||||
- Label:
|
||||
default: CodeBuild Settings
|
||||
Parameters:
|
||||
- ProwlerCodeBuildAccount
|
||||
- ProwlerCodeBuildRole
|
||||
- Label:
|
||||
default: S3 Settings
|
||||
Parameters:
|
||||
- ProwlerS3
|
||||
- Label:
|
||||
default: CrossAccount Role
|
||||
Parameters:
|
||||
- ProwlerCrossAccountRole
|
||||
|
||||
Parameters:
|
||||
ProwlerS3:
|
||||
Type: String
|
||||
Description: Enter S3 Bucket for Prowler Reports. prefix-awsaccount-awsregion
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$
|
||||
Default: prowler-954896828174-ap-northeast-2
|
||||
ProwlerCodeBuildAccount:
|
||||
Type: String
|
||||
Description: Enter AWS Account Number where Prowler CodeBuild Instance will reside.
|
||||
AllowedPattern: ^\d{12}$
|
||||
ConstraintDescription: An AWS Account Number must be a 12 digit numeric string.
|
||||
Default: 411267690458
|
||||
ProwlerCodeBuildRole:
|
||||
Type: String
|
||||
Description: Enter Instance Role that will be given to the Prowler CodeBuild (needed to grant sts:AssumeRole rights).
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerCodeBuild-Role
|
||||
ProwlerCrossAccountRole:
|
||||
Type: String
|
||||
Description: Enter Name for CrossAccount Role to be created for Prowler to assess all Accounts in the AWS Organization.
|
||||
AllowedPattern: ^[\w+=,.@-]{1,64}$
|
||||
ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
|
||||
Default: ProwlerXA-CBRole
|
||||
|
||||
Resources:
|
||||
ProwlerRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
Description: Provides Prowler CodeBuild permissions to assess security of Accounts in AWS Organization
|
||||
RoleName: !Ref ProwlerCrossAccountRole
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
AWS:
|
||||
- !Sub arn:${AWS::Partition}:iam::${ProwlerCodeBuildAccount}:root
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Condition:
|
||||
StringLike:
|
||||
aws:PrincipalArn: !Sub arn:${AWS::Partition}:iam::${ProwlerCodeBuildAccount}:role/${ProwlerCodeBuildRole}
|
||||
ManagedPolicyArns:
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/SecurityAudit
|
||||
- !Sub arn:${AWS::Partition}:iam::aws:policy/job-function/ViewOnlyAccess
|
||||
Policies:
|
||||
- PolicyName: Prowler-Additions-Policy
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowMoreReadForProwler
|
||||
Effect: Allow
|
||||
Resource: "*"
|
||||
Action:
|
||||
- access-analyzer:List*
|
||||
- apigateway:Get*
|
||||
- apigatewayv2:Get*
|
||||
- aws-marketplace:ViewSubscriptions
|
||||
- dax:ListTables
|
||||
- ds:ListAuthorizedApplications
|
||||
- ds:DescribeRoles
|
||||
- ec2:GetEbsEncryptionByDefault
|
||||
- ecr:Describe*
|
||||
- lambda:GetAccountSettings
|
||||
- lambda:GetFunctionConfiguration
|
||||
- lambda:GetLayerVersionPolicy
|
||||
- lambda:GetPolicy
|
||||
- opsworks-cm:Describe*
|
||||
- opsworks:Describe*
|
||||
- secretsmanager:ListSecretVersionIds
|
||||
- sns:List*
|
||||
- sqs:ListQueueTags
|
||||
- states:ListActivities
|
||||
- support:Describe*
|
||||
- tag:GetTagKeys
|
||||
- shield:GetSubscriptionState
|
||||
- shield:DescribeProtection
|
||||
- elasticfilesystem:DescribeBackupPolicy
|
||||
- PolicyName: Prowler-S3-Reports
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W11
|
||||
reason: "Prowler requires these rights to perform its Security Assessment."
|
||||
- id: W28
|
||||
reason: "Using a defined Role Name."
|
||||
|
||||
Outputs:
|
||||
ProwlerCrossAccountRole:
|
||||
Description: CrossAccount Role to be used by Prowler to assess AWS Accounts in the AWS Organization.
|
||||
Value: !Ref ProwlerCrossAccountRole
|
||||
@@ -0,0 +1,106 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Create Prowler S3 Bucket for Prowler Reports
|
||||
|
||||
Parameters:
|
||||
AwsOrgId:
|
||||
Type: String
|
||||
Description: >
|
||||
Enter AWS Organizations ID.
|
||||
This is used to restrict permissions to least privilege.
|
||||
AllowedPattern: ^o-[a-z0-9]{10,32}$
|
||||
ConstraintDescription: The Org Id must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters.
|
||||
Default: o-abcde12345
|
||||
S3Prefix:
|
||||
Type: String
|
||||
Description: >
|
||||
Enter S3 Bucket Name Prefix (in lowercase).
|
||||
Bucket will be named: prefix-awsaccount-awsregion (i.e., prowler-123456789012-us-east-1)
|
||||
AllowedPattern: ^[a-z0-9][a-z0-9-]{1,33}[a-z0-9]$
|
||||
ConstraintDescription: >
|
||||
Max 35 characters, as "-awsaccount-awsregion" will be added, and max name is 63 characters.
|
||||
Can't start or end with dash. Can use numbers and lowercase letters.
|
||||
Default: prowler
|
||||
|
||||
Resources:
|
||||
ProwlerS3:
|
||||
Type: AWS::S3::Bucket
|
||||
Properties:
|
||||
BucketName: !Sub ${S3Prefix}-${AWS::AccountId}-${AWS::Region}
|
||||
BucketEncryption:
|
||||
ServerSideEncryptionConfiguration:
|
||||
- ServerSideEncryptionByDefault:
|
||||
SSEAlgorithm: "AES256"
|
||||
AccessControl: Private
|
||||
PublicAccessBlockConfiguration:
|
||||
BlockPublicAcls: True
|
||||
BlockPublicPolicy: True
|
||||
IgnorePublicAcls: True
|
||||
RestrictPublicBuckets: True
|
||||
VersioningConfiguration:
|
||||
Status: Enabled
|
||||
Tags:
|
||||
- Key: App
|
||||
Value: Prowler
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W35
|
||||
reason: "This S3 Bucket is only being used by the AWS Organization to download/upload prowler reports."
|
||||
|
||||
ProwlerS3BucketPolicy:
|
||||
Type: AWS::S3::BucketPolicy
|
||||
Properties:
|
||||
Bucket: !Ref ProwlerS3
|
||||
PolicyDocument:
|
||||
Statement:
|
||||
- Sid: AllowGetPutListObject
|
||||
Effect: Allow
|
||||
Principal: "*"
|
||||
Action:
|
||||
- s3:GetObject
|
||||
- s3:PutObject
|
||||
- s3:ListBucket
|
||||
- s3:PutObjectAcl
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Condition:
|
||||
StringEquals:
|
||||
aws:PrincipalOrgId: !Ref AwsOrgId
|
||||
- Sid: DenyNonSSLRequests
|
||||
Effect: Deny
|
||||
Action: s3:*
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
Principal: "*"
|
||||
Condition:
|
||||
Bool:
|
||||
aws:SecureTransport: false
|
||||
- Sid: DenyIncorrectEncryptionHeader
|
||||
Effect: Deny
|
||||
Principal: "*"
|
||||
Action: s3:PutObject
|
||||
Resource:
|
||||
- !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/*
|
||||
# Allow uploads with No Encryption, as S3 Default Encryption still applies.
|
||||
# If Encryption is set, only allow uploads with AES256.
|
||||
Condition:
|
||||
"Null":
|
||||
s3:x-amz-server-side-encryption: false
|
||||
StringNotEquals:
|
||||
s3:x-amz-server-side-encryption: AES256
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: F16
|
||||
reason: "This S3 Bucket Policy has a condition that only allows access to the AWS Organization."
|
||||
|
||||
|
||||
Outputs:
|
||||
ProwlerS3:
|
||||
Description: S3 Bucket for Prowler Reports
|
||||
Value: !Ref ProwlerS3
|
||||
ProwlerS3Account:
|
||||
Description: AWS Account Number where Prowler S3 Bucket resides.
|
||||
Value: !Ref AWS::AccountId
|
||||
115
contrib/org-multi-account/src/run-prowler-reports.sh
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Run Prowler against All AWS Accounts in an AWS Organization
|
||||
|
||||
# Change Directory (rest of the script, assumes your in the ec2-user home directory)
|
||||
cd /home/ec2-user || exit
|
||||
|
||||
# Show Prowler Version, and Download Prowler, if it doesn't already exist
|
||||
if ! ./prowler/prowler -V 2>/dev/null; then
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
./prowler/prowler -V
|
||||
fi
|
||||
|
||||
# Source .awsvariables (to read in Environment Variables from CloudFormation Data)
|
||||
# shellcheck disable=SC1091
|
||||
source .awsvariables
|
||||
|
||||
# Get Values from Environment Variables Created on EC2 Instance from CloudFormation Data
|
||||
echo "S3: $S3"
|
||||
echo "S3ACCOUNT: $S3ACCOUNT"
|
||||
echo "ROLE: $ROLE"
|
||||
|
||||
# CleanUp Last Ran Prowler Reports, as they are already stored in S3.
|
||||
rm -rf prowler/output/*.html
|
||||
|
||||
# Function to unset AWS Profile Variables
|
||||
unset_aws() {
|
||||
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
unset_aws
|
||||
|
||||
# Find THIS Account AWS Number
|
||||
CALLER_ARN=$(aws sts get-caller-identity --output text --query "Arn")
|
||||
PARTITION=$(echo "$CALLER_ARN" | cut -d: -f2)
|
||||
THISACCOUNT=$(echo "$CALLER_ARN" | cut -d: -f5)
|
||||
echo "THISACCOUNT: $THISACCOUNT"
|
||||
echo "PARTITION: $PARTITION"
|
||||
|
||||
# Function to Assume Role to THIS Account & Create Session
|
||||
this_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$THISACCOUNT":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Find AWS Master Account
|
||||
this_account_session
|
||||
AWSMASTER=$(aws organizations describe-organization --query Organization.MasterAccountId --output text)
|
||||
echo "AWSMASTER: $AWSMASTER"
|
||||
|
||||
# Function to Assume Role to Master Account & Create Session
|
||||
master_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$AWSMASTER":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Lookup All Accounts in AWS Organization
|
||||
master_account_session
|
||||
ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[*].Id --output text)
|
||||
|
||||
# Function to Assume Role to S3 Account & Create Session
|
||||
s3_account_session() {
|
||||
unset_aws
|
||||
role_credentials=$(aws sts assume-role --role-arn arn:"$PARTITION":iam::"$S3ACCOUNT":role/"$ROLE" --role-session-name ProwlerRun --output json)
|
||||
AWS_ACCESS_KEY_ID=$(echo "$role_credentials" | jq -r .Credentials.AccessKeyId)
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$role_credentials" | jq -r .Credentials.SecretAccessKey)
|
||||
AWS_SESSION_TOKEN=$(echo "$role_credentials" | jq -r .Credentials.SessionToken)
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
|
||||
}
|
||||
|
||||
# Run Prowler against Accounts in AWS Organization
|
||||
echo "AWS Accounts in Organization"
|
||||
echo "$ACCOUNTS_IN_ORGS"
|
||||
PARALLEL_ACCOUNTS="1"
|
||||
for accountId in $ACCOUNTS_IN_ORGS; do
|
||||
# shellcheck disable=SC2015
|
||||
test "$(jobs | wc -l)" -ge $PARALLEL_ACCOUNTS && wait || true
|
||||
{
|
||||
START_TIME=$SECONDS
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
# Run Prowler
|
||||
echo -e "Assessing AWS Account: $accountId, using Role: $ROLE on $(date)"
|
||||
# remove -g cislevel for a full report and add other formats if needed
|
||||
./prowler/prowler -R "$ROLE" -A "$accountId" -g cislevel1 -M html -z
|
||||
echo "Report stored locally at: prowler/output/ directory"
|
||||
TOTAL_SEC=$((SECONDS - START_TIME))
|
||||
echo -e "Completed AWS Account: $accountId, using Role: $ROLE on $(date)"
|
||||
printf "Completed AWS Account: $accountId in %02dh:%02dm:%02ds" $((TOTAL_SEC / 3600)) $((TOTAL_SEC % 3600 / 60)) $((TOTAL_SEC % 60))
|
||||
echo ""
|
||||
} &
|
||||
done
|
||||
|
||||
# Wait for All Prowler Processes to finish
|
||||
wait
|
||||
echo "Prowler Assessments Completed against All Accounts in the AWS Organization. Starting S3 copy operations..."
|
||||
|
||||
# Upload Prowler Report to S3
|
||||
s3_account_session
|
||||
aws s3 cp prowler/output/ "$S3/reports/" --recursive --include "*.html" --acl bucket-owner-full-control
|
||||
echo "Assessment reports successfully copied to S3 bucket"
|
||||
|
||||
# Final Wait for All Prowler Processes to finish
|
||||
wait
|
||||
echo "Prowler Assessments Completed"
|
||||
|
||||
# Unset AWS Profile Variables
|
||||
unset_aws
|
||||
75
contrib/other-contrib/multi-account/Audit_Exec_Role.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: Prowler Auditing Role - in Control Tower pick AWSControlTowerStackSetRole for IAM role and AWSControlTowerExecution for execution
|
||||
|
||||
Parameters:
|
||||
|
||||
AuditorAccountId:
|
||||
Default: 987600001234
|
||||
Description: AWS Account ID where the audit tooling executes
|
||||
Type: Number
|
||||
AuditRolePathName:
|
||||
Default: '/audit/prowler/XA_AuditRole_Prowler'
|
||||
Description: Path for role name in audit tooling account
|
||||
Type: String
|
||||
|
||||
Resources:
|
||||
XAAuditRole:
|
||||
Type: "AWS::IAM::Role"
|
||||
Properties: # /audit/prowler/XA_AuditRole_Prowler
|
||||
RoleName: XA_AuditRole_Prowler
|
||||
Path: "/audit/prowler/"
|
||||
ManagedPolicyArns:
|
||||
- arn:aws:iam::aws:policy/SecurityAudit
|
||||
- arn:aws:iam::aws:policy/AWSOrganizationsReadOnlyAccess
|
||||
- arn:aws:iam::aws:policy/IAMReadOnlyAccess
|
||||
AssumeRolePolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Effect: "Allow"
|
||||
Principal:
|
||||
AWS: # TODO: review permissions to see if this can be narrowed down - code build only perhaps
|
||||
- !Sub "arn:aws:iam::${AuditorAccountId}:root"
|
||||
Action:
|
||||
- "sts:AssumeRole"
|
||||
- Effect: "Allow"
|
||||
Principal:
|
||||
Service:
|
||||
- "codebuild.amazonaws.com"
|
||||
Action:
|
||||
- "sts:AssumeRole"
|
||||
# TODO: restrict to only AuditorAccount only
|
||||
Policies:
|
||||
- PolicyName: "ProwlerPolicyAdditions"
|
||||
PolicyDocument:
|
||||
Version: "2012-10-17"
|
||||
Statement:
|
||||
- Sid: "ProwlerPolicyAdditions"
|
||||
Effect: "Allow"
|
||||
Resource: "*"
|
||||
Action:
|
||||
- "acm:describecertificate"
|
||||
- "acm:listcertificates"
|
||||
- "apigateway:GET"
|
||||
- "cloudtrail:GetEventSelectors"
|
||||
- "ec2:GetEbsEncryptionByDefault"
|
||||
- "es:describeelasticsearchdomainconfig"
|
||||
- "guardduty:ListDetectors"
|
||||
- "guardduty:GetDetector"
|
||||
- "logs:DescribeLogGroups"
|
||||
- "logs:DescribeMetricFilters"
|
||||
- "s3:GetEncryptionConfiguration"
|
||||
- "ses:getidentityverificationattributes"
|
||||
- "sns:listsubscriptionsbytopic"
|
||||
- "support:*"
|
||||
- "trustedadvisor:Describe*"
|
||||
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W28
|
||||
reason: "the role name is intentionally static"
|
||||
- id: W11
|
||||
reason: "the policy grants read/view/audit access only, to all resources, by design"
|
||||
- id: F3
|
||||
reason: "Support does not allow or deny access to individual actions"
|
||||
411
contrib/other-contrib/multi-account/Audit_Pipeline.yaml
Normal file
@@ -0,0 +1,411 @@
|
||||
---
|
||||
AWSTemplateFormatVersion: '2010-09-09'
|
||||
Description: Prowler Auditing Tools Stack
|
||||
|
||||
Metadata:
|
||||
AWS::CloudFormation::Interface:
|
||||
ParameterGroups:
|
||||
- Label:
|
||||
default: "Organizations and Accounts"
|
||||
Parameters:
|
||||
- pOrgMasterAccounts
|
||||
- pOrgExcludedAccounts
|
||||
- pStandAloneAccounts
|
||||
- Label:
|
||||
default: "Check Group and Execution"
|
||||
Parameters:
|
||||
- pProwlerCheckGroup
|
||||
- pAuditEveryXHours
|
||||
- Label:
|
||||
default: "Advanced"
|
||||
Parameters:
|
||||
- pTimeoutMinutes
|
||||
- pAuditRolePathName
|
||||
- pCustomProwlerRepo
|
||||
- pCustomProwlerCloneArgs
|
||||
ParameterLabels:
|
||||
pOrgMasterAccounts:
|
||||
default: "Organization Master Accounts"
|
||||
pOrgExcludedAccounts:
|
||||
default: "Excluded Organiztion Members"
|
||||
pStandAloneAccounts:
|
||||
default: "Stand-alone Accounts"
|
||||
pProwlerCheckGroup:
|
||||
default: "Prowler Check Group"
|
||||
pAuditEveryXHours:
|
||||
default: "Perform Audit every X hours"
|
||||
pTimeoutMinutes:
|
||||
default: "Permit Audit to run for X minutes"
|
||||
pAuditRolePathName:
|
||||
default: "Custom audit role path"
|
||||
pCustomProwlerRepo:
|
||||
default: "Custom git repo location for prowler"
|
||||
pCustomProwlerCloneArgs:
|
||||
default: "Custom arguments to git clone --depth 1"
|
||||
|
||||
Parameters:
|
||||
pAuditEveryXHours:
|
||||
Default: 24
|
||||
Type: Number
|
||||
Description: Number of hours between prowler audit runs.
|
||||
MinValue: 2
|
||||
MaxValue: 168
|
||||
pTimeoutMinutes:
|
||||
Default: 30
|
||||
Type: Number
|
||||
Description: Timeout for running prowler across the fleet
|
||||
MinValue: 5
|
||||
MaxValue: 480
|
||||
pAuditRolePathName:
|
||||
Default: '/audit/prowler/XA_AuditRole_Prowler'
|
||||
Type: String
|
||||
Description: Role path and name which prowler will assume in the target accounts (Audit_Exec_Role.yaml)
|
||||
# TODO: Validation: begins with "/" and does NOT end with "/"
|
||||
pOrgMasterAccounts:
|
||||
Description: Comma Separated list of Organization Master Accounts, or 'none'
|
||||
Default: 'none'
|
||||
Type: String
|
||||
MinLength: 4
|
||||
AllowedPattern: ^(none|([0-9]{12}(,[0-9]{12})*))$
|
||||
ConstraintDescription: comma separated list 12-digit account numbers, or 'none'
|
||||
pOrgExcludedAccounts: # Comma Separated list of Org Member Accounts to EXCLUDE
|
||||
Description: Comma Separated list of Skipped Organization Member Accounts, or 'none'
|
||||
Default: 'none'
|
||||
Type: String
|
||||
MinLength: 4
|
||||
AllowedPattern: ^(none|([0-9]{12}(,[0-9]{12})*))$
|
||||
ConstraintDescription: comma separated list 12-digit account numbers, or 'none'
|
||||
pStandAloneAccounts: # Comma Separated list of Stand-Alone Accounts
|
||||
Description: Comma Separated list of Stand-alone Accounts, or 'none'
|
||||
Default: 'none'
|
||||
Type: String
|
||||
MinLength: 4
|
||||
AllowedPattern: ^(none|([0-9]{12}(,[0-9]{12})*))$
|
||||
ConstraintDescription: comma separated list 12-digit account numbers, or 'none'
|
||||
pProwlerCheckGroup:
|
||||
Default: 'cislevel1'
|
||||
Type: String
|
||||
Description: Which group of checks should prowler run
|
||||
AllowedValues:
|
||||
- 'group1'
|
||||
- 'group2'
|
||||
- 'group3'
|
||||
- 'group4'
|
||||
- 'cislevel1'
|
||||
- 'cislevel2'
|
||||
- 'extras'
|
||||
- 'forensics-ready'
|
||||
- 'gdpr'
|
||||
- 'hipaa'
|
||||
- 'secrets'
|
||||
- 'apigateway'
|
||||
- 'rds'
|
||||
pCustomProwlerRepo:
|
||||
Type: String
|
||||
Default: 'https://github.com/prowler-cloud/prowler.git'
|
||||
MinLength: 10
|
||||
pCustomProwlerCloneArgs:
|
||||
Type: String
|
||||
Default: '--branch master'
|
||||
MinLength: 0
|
||||
##### TODO
|
||||
# pResultsBucket: # if specified, use an existing bucket for the data
|
||||
# pEnableAthena:
|
||||
# Default: false
|
||||
# Type: Boolean
|
||||
# Description: Set to true to enable creation of Athena/QuickSight resources
|
||||
|
||||
#### TODO
|
||||
# Conditions:
|
||||
# cUseAthena: False
|
||||
|
||||
Resources:
|
||||
|
||||
# S3 Bucket for Results, Config
|
||||
ProwlerResults:
|
||||
Type: "AWS::S3::Bucket"
|
||||
Properties:
|
||||
# BucketName: !Sub "audit-results-${AWS::AccountId}"
|
||||
Tags:
|
||||
- Key: "data-type"
|
||||
Value: "it-audit:sensitive"
|
||||
- Key: "data-public"
|
||||
Value: "NO"
|
||||
AccessControl: Private
|
||||
BucketEncryption:
|
||||
ServerSideEncryptionConfiguration:
|
||||
- ServerSideEncryptionByDefault:
|
||||
SSEAlgorithm: AES256
|
||||
PublicAccessBlockConfiguration:
|
||||
BlockPublicAcls: True
|
||||
BlockPublicPolicy: True
|
||||
IgnorePublicAcls: True
|
||||
RestrictPublicBuckets: True
|
||||
# LoggingConfiguration:
|
||||
# TODO: Enable BucketLogging - requires more parameters
|
||||
DeletionPolicy: "Retain"
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W35
|
||||
reason: "Bucket logging requires additional configuration not yet supported by this template"
|
||||
|
||||
# Policy to allow assuming the XA_AuditRole_Prowler in target accounts
|
||||
ProwlerAuditManagerRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
RoleName: AuditManagerRole_Prowler
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: codebuild.amazonaws.com
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Path: /
|
||||
Policies:
|
||||
- PolicyName: AssumeRole-XA_AuditRole_Prowler
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Resource:
|
||||
- !Sub "arn:aws:iam::*:role${pAuditRolePathName}"
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- s3:PutObject
|
||||
- s3:GetObject
|
||||
- s3:GetObjectVersion
|
||||
Resource:
|
||||
- !Sub "${ProwlerResults.Arn}/*"
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- s3:ListBucket
|
||||
- s3:HeadBucket
|
||||
- s3:GetBucketLocation
|
||||
- s3:GetBucketAcl
|
||||
Resource:
|
||||
- !Sub "${ProwlerResults.Arn}"
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- logs:CreateLogGroup
|
||||
- logs:CreateLogStream
|
||||
- logs:PutLogEvents
|
||||
Resource:
|
||||
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*"
|
||||
- !Sub "${ProwlerResults.Arn}"
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- ssm:GetParameters
|
||||
Resource:
|
||||
- !Sub "arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/audit/prowler/config/*"
|
||||
Metadata:
|
||||
cfn_nag:
|
||||
rules_to_suppress:
|
||||
- id: W28
|
||||
reason: "the role name is intentionally static"
|
||||
- id: W11
|
||||
reason: "not sure where the violation of w11 is"
|
||||
|
||||
## Code Build Job
|
||||
ProwlerBuildProject:
|
||||
Type: "AWS::CodeBuild::Project"
|
||||
Properties:
|
||||
Name: PerformProwlerAudit
|
||||
Description: "Run Prowler audit on accounts in targeted organizations"
|
||||
QueuedTimeoutInMinutes: 480
|
||||
TimeoutInMinutes: !Ref pTimeoutMinutes
|
||||
ServiceRole: !Ref ProwlerAuditManagerRole
|
||||
EncryptionKey: !Sub "arn:aws:kms:us-east-1:${AWS::AccountId}:alias/aws/s3"
|
||||
Environment:
|
||||
Type: "LINUX_CONTAINER"
|
||||
ComputeType: "BUILD_GENERAL1_MEDIUM"
|
||||
PrivilegedMode: False
|
||||
Image: "aws/codebuild/standard:2.0-1.12.0"
|
||||
ImagePullCredentialsType: "CODEBUILD"
|
||||
Artifacts: # s3://stack-prowlerresults-randomness/prowler/results/...
|
||||
Name: "results"
|
||||
Type: "S3"
|
||||
Location: !Ref ProwlerResults
|
||||
Path: "prowler"
|
||||
NamespaceType: NONE
|
||||
Packaging: NONE
|
||||
OverrideArtifactName: False
|
||||
EncryptionDisabled: False
|
||||
LogsConfig: # S3/logs/pipeline/
|
||||
CloudWatchLogs:
|
||||
Status: ENABLED
|
||||
GroupName: "audit/prowler"
|
||||
StreamName: "codebuild_runs"
|
||||
S3Logs:
|
||||
Status: DISABLED
|
||||
# Location: !Sub "${ProwlerResults.Arn}/codebuild_run_logs"
|
||||
EncryptionDisabled: False
|
||||
BadgeEnabled: False
|
||||
Tags:
|
||||
- Key: "data-type"
|
||||
Value: "it-audit:sensitive"
|
||||
- Key: "data-public"
|
||||
Value: "NO"
|
||||
Cache:
|
||||
Type: "NO_CACHE"
|
||||
Source:
|
||||
Type: NO_SOURCE
|
||||
BuildSpec: |
|
||||
version: 0.2
|
||||
env:
|
||||
parameter-store:
|
||||
PROWL_CHECK_GROUP: /audit/prowler/config/check_group
|
||||
PROWL_MASTER_ACCOUNTS: /audit/prowler/config/orgmaster_accounts
|
||||
PROWL_STANDALONE_ACCOUNTS: /audit/prowler/config/standalone_accounts
|
||||
PROWL_SKIP_ACCOUNTS: /audit/prowler/config/skip_accounts
|
||||
PROWL_AUDIT_ROLE: /audit/prowler/config/audit_role
|
||||
PROWLER_REPO: /audit/prowler/config/gitrepo
|
||||
PROWLER_CLONE_ARGS: /audit/prowler/config/gitcloneargs
|
||||
phases:
|
||||
install:
|
||||
runtime-versions:
|
||||
python: 3.7
|
||||
commands:
|
||||
- aws --version
|
||||
- git clone --depth 1 $PROWLER_REPO $PROWLER_CLONE_ARGS
|
||||
pre_build:
|
||||
commands:
|
||||
- env | grep PROWL_
|
||||
- export OUTBASE=$(date -u +"out/diagnostics/%Y/%m/%d")
|
||||
- export STAMP=$(date -u +"%Y%m%dT%H%M%SZ")
|
||||
- mkdir -p $OUTBASE || true
|
||||
- prowler/prowler -V
|
||||
- aws sts get-caller-identity > ${OUTBASE}/${STAMP}-caller-id.json
|
||||
build:
|
||||
commands:
|
||||
#### Run Prowler against this account, but don't fail the build
|
||||
# - export PROWLER_ACCOUNT_ID=$(aws sts get-caller-identity | jq -r '.Account')
|
||||
# - /bin/bash prowler/prowler -g cislevel1 -M csv -n -k > ${OUTBASE}/${STAMP}.${PROWLER_ACCOUNT_ID}.prowler.cislevel1.csv || /bin/true
|
||||
# - /bin/bash prowler/prowler -g forensics-ready -M csv -n -k > ${OUTBASE}/${STAMP}.${PROWLER_ACCOUNT_ID}.prowler.forensics-ready.csv || /bin/true
|
||||
#### Run Prowler targeting all accounts in the configured organizations
|
||||
- test -f prowler/util/multi-account/config
|
||||
- /bin/bash prowler/util/multi-account/megaprowler.sh out
|
||||
finally:
|
||||
- ps axuwww | grep -E 'parallel|sem|prowler'
|
||||
post_build:
|
||||
commands:
|
||||
- echo "attempting to collect any prowler credential reports ..."
|
||||
- find /tmp/ -name prowler\* | xargs -I % cp % ${OUTDIAG} || true
|
||||
artifacts:
|
||||
files:
|
||||
- '**/*'
|
||||
discard-paths: no
|
||||
base-directory: out
|
||||
|
||||
ProwlerAuditTriggerRole:
|
||||
Type: AWS::IAM::Role
|
||||
Properties:
|
||||
# RoleName: Let cloudformation create this
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service: events.amazonaws.com
|
||||
Action:
|
||||
- sts:AssumeRole
|
||||
Path: /
|
||||
Policies:
|
||||
- PolicyName: AssumeRole-XA_AuditRole_Prowler
|
||||
PolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Action:
|
||||
- codebuild:StartBuild
|
||||
Resource:
|
||||
- !GetAtt ProwlerBuildProject.Arn
|
||||
|
||||
ProwlerAuditTrigger:
|
||||
Type: AWS::Events::Rule
|
||||
Properties:
|
||||
Description: !Sub "Execute Prowler audit every ${pAuditEveryXHours} hours"
|
||||
Name: "ScheduledProwler"
|
||||
RoleArn: !GetAtt ProwlerAuditTriggerRole.Arn
|
||||
## Other ways to define scheduling
|
||||
# ScheduleExpression: "cron(MM HH ? * * *)"
|
||||
# ScheduleExpression: "cron(45 15 ? * * *)"
|
||||
# ScheduleExpression: !Sub "rate( ${pAuditEveryXHours} hours)"
|
||||
ScheduleExpression: !Sub "rate(${pAuditEveryXHours} hours)"
|
||||
State: ENABLED
|
||||
Targets:
|
||||
- Arn: !GetAtt ProwlerBuildProject.Arn
|
||||
Id: 'ScheduledProwler'
|
||||
RoleArn: !GetAtt ProwlerAuditTriggerRole.Arn
|
||||
|
||||
ProwlerConfigCheckGroup:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "Name of the prowler check group to use"
|
||||
Name: "/audit/prowler/config/check_group"
|
||||
Type: "String"
|
||||
Value: !Ref pProwlerCheckGroup
|
||||
|
||||
ProwlerConfigMasterAccounts:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "List of organization master accounts"
|
||||
Name: "/audit/prowler/config/orgmaster_accounts"
|
||||
Type: "String"
|
||||
Value: !Ref pOrgMasterAccounts
|
||||
|
||||
ProwlerConfigStandAloneAccounts:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "List of stand-alone accounts"
|
||||
Name: "/audit/prowler/config/standalone_accounts"
|
||||
Type: "String"
|
||||
Value: !Ref pStandAloneAccounts
|
||||
|
||||
ProwlerConfigSkipAccounts:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "List of skipped organization member accounts"
|
||||
Name: "/audit/prowler/config/skip_accounts"
|
||||
Type: "String"
|
||||
Value: !Ref pOrgExcludedAccounts
|
||||
|
||||
ProwlerConfigAuditRole:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "Role used to audit target accounts"
|
||||
Name: "/audit/prowler/config/audit_role"
|
||||
Type: "String"
|
||||
Value: !Ref pAuditRolePathName
|
||||
|
||||
ProwlerConfigGitRepo:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "Git repository where prowler is gathered"
|
||||
Name: "/audit/prowler/config/gitrepo"
|
||||
Type: "String"
|
||||
Value: !Ref pCustomProwlerRepo
|
||||
|
||||
ProwlerConfigGitCloneArgs:
|
||||
Type: AWS::SSM::Parameter
|
||||
Properties:
|
||||
Description: "Git clone arguments"
|
||||
Name: "/audit/prowler/config/gitcloneargs"
|
||||
Type: "String"
|
||||
Value: !Ref pCustomProwlerCloneArgs
|
||||
|
||||
|
||||
# -- Conditional "cUseAthena"
|
||||
# Athena
|
||||
# QuickSight
|
||||
# ???
|
||||
|
||||
|
||||
Outputs:
|
||||
ResultsBucket:
|
||||
Description: S3 Bucket with Prowler Results, Logs, Configs
|
||||
Value: !Ref ProwlerResults
|
||||
33
contrib/other-contrib/multi-account/config
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
########### CODEBUILD CONFIGURATION ##################
|
||||
# shellcheck disable=SC2034
|
||||
## Collect environment parameters set by buildspec
|
||||
CHECKGROUP=${PROWL_CHECK_GROUP}
|
||||
|
||||
if [ "none" == "${PROWL_MASTER_ACCOUNTS}" ]; then
|
||||
ORG_MASTERS=""
|
||||
else
|
||||
ORG_MASTERS=$(echo "${PROWL_MASTER_ACCOUNTS}" | tr "," " ")
|
||||
fi
|
||||
|
||||
if [ "none" == "${PROWL_STANDALONE_ACCOUNTS}" ]; then
|
||||
STANDALONE_ACCOUNTS=""
|
||||
else
|
||||
STANDALONE_ACCOUNTS=$(echo "${PROWL_STANDALONE_ACCOUNTS}" | tr "," " ")
|
||||
fi
|
||||
|
||||
if [ "none" == "${PROWL_SKIP_ACCOUNTS}" ]; then
|
||||
SKIP_ACCOUNTS_REGEX='^$'
|
||||
else
|
||||
skip_inside=$(echo "${PROWL_SKIP_ACCOUNTS}" | tr "," "|")
|
||||
# shellcheck disable=SC2116
|
||||
SKIP_ACCOUNTS_REGEX=$(echo "(${skip_inside})" )
|
||||
fi
|
||||
|
||||
AUDIT_ROLE=${PROWL_AUDIT_ROLE}
|
||||
|
||||
# Adjust if you clone prowler from somewhere other than the default location
|
||||
PROWLER='prowler/prowler'
|
||||
|
||||
# Change this if you want to ensure it breaks in code build
|
||||
CREDSOURCE='EcsContainer'
|
||||
202
contrib/other-contrib/multi-account/megaprowler.sh
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASEDIR=$(dirname "${0}")
|
||||
# source the configuration data from "config" in this directory
|
||||
if [[ -f "${BASEDIR}/config" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "${BASEDIR}/config"
|
||||
|
||||
else
|
||||
echo "CONFIG file missing - ${BASEDIR}/config"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
## Check Environment variables which are set by config
|
||||
if [[ "${ORG_MASTERS}X" == "X" && "${STANDALONE_ACCOUNTS}X" == "X" ]]; then
|
||||
echo "No audit targets specified. Failing."
|
||||
exit 15
|
||||
fi
|
||||
if [[ -z $SKIP_ACCOUNTS_REGEX ]]; then
|
||||
SKIP_ACCOUNTS_REGEX=""
|
||||
fi
|
||||
|
||||
if [[ -z $CHECKGROUP ]]; then
|
||||
echo "Missing check group from config file"
|
||||
exit 255
|
||||
fi
|
||||
if [[ -z $AUDIT_ROLE ]]; then
|
||||
echo "Missing audit role from config file"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
## ========================================================================================
|
||||
|
||||
## Check Arguments
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "NEED AN OUTPUT DIRECTORY"
|
||||
exit 2
|
||||
else
|
||||
if [[ -d $1 && -w $1 ]]; then
|
||||
OUTBASE=$1
|
||||
else
|
||||
echo "Output directory missing or write-protected"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
## Check Requirements
|
||||
if [[ -x $(command -v aws) ]]; then
|
||||
aws --version
|
||||
else
|
||||
echo "AWS CLI is not in PATH ... giving up"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if [[ -x $(command -v jq) ]]; then
|
||||
jq --version
|
||||
else
|
||||
echo "JQ is not in PATH ... giving up"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
# Ensure AWS Credentials are present in environment
|
||||
if [[ -z $CREDSOURCE ]]; then
|
||||
echo "No source for base credentials ... giving up"
|
||||
exit 5
|
||||
fi
|
||||
|
||||
if [[ -f ${PROWLER} && -x ${PROWLER} ]]; then
|
||||
${PROWLER} -V
|
||||
else
|
||||
echo "Unable to execute prowler from ${PROWLER}"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
|
||||
## Preflight checks complete
|
||||
|
||||
DAYPATH=$(date -u +%Y/%m/%d)
|
||||
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
## Create output subdirs
|
||||
OUTDATA="${OUTBASE}/data/${DAYPATH}"
|
||||
OUTLOGS="${OUTBASE}/logs/${DAYPATH}"
|
||||
mkdir -p "${OUTDATA}" "${OUTLOGS}"
|
||||
|
||||
|
||||
if [[ -x $(command -v parallel) ]]; then
|
||||
# Note: the "standard" codebuild container includes parallel
|
||||
echo "Using GNU sem/parallel, with NCPU+4 jobs"
|
||||
parallel --citation > /dev/null 2> /dev/null
|
||||
PARALLEL_START="parallel --semaphore --fg --id p_${STAMP} --jobs +4 --env AWS_SHARED_CREDENTIALS_FILE"
|
||||
PARALLEL_START_SUFFIX=''
|
||||
PARALLEL_END="parallel --semaphore --wait --id p_${STAMP}"
|
||||
else
|
||||
echo "Consider installing GNU Parallel to avoid punishing your system"
|
||||
PARALLEL_START=''
|
||||
PARALLEL_START_SUFFIX=' &'
|
||||
# shellcheck disable=SC2089
|
||||
PARALLEL_END="echo 'WAITING BLINDLY FOR PROCESSES TO COMPLETE'; wait ; sleep 30 ; wait"
|
||||
fi
|
||||
|
||||
echo "Execution Timestamp: ${STAMP}"
|
||||
|
||||
ALL_ACCOUNTS=""
|
||||
|
||||
|
||||
# Create a temporary credential file
|
||||
AWS_MASTERS_CREDENTIALS_FILE=$(mktemp -t prowler.masters-XXXXXX)
|
||||
echo "Preparing Credentials ${AWS_MASTERS_CREDENTIALS_FILE} ( ${CREDSOURCE} )"
|
||||
echo "# Master Credentials ${STAMP}" >> "${AWS_MASTERS_CREDENTIALS_FILE}"
|
||||
echo "" >> "${AWS_MASTERS_CREDENTIALS_FILE}"
|
||||
|
||||
AWS_TARGETS_CREDENTIALS_FILE=$(mktemp -t prowler.targets-XXXXXX)
|
||||
echo "Preparing Credentials ${AWS_TARGETS_CREDENTIALS_FILE} ( ${CREDSOURCE} )"
|
||||
echo "# Target Credentials ${STAMP}" >> "${AWS_TARGETS_CREDENTIALS_FILE}"
|
||||
echo "" >> "${AWS_TARGETS_CREDENTIALS_FILE}"
|
||||
|
||||
|
||||
## Visit the Organization Master accounts & build a list of all member accounts
|
||||
export AWS_SHARED_CREDENTIALS_FILE=$AWS_MASTERS_CREDENTIALS_FILE
|
||||
for org in $ORG_MASTERS ; do
|
||||
echo -n "Preparing organization $org "
|
||||
# create credential profile
|
||||
{
|
||||
echo "[audit_${org}]"
|
||||
echo "role_arn = arn:aws:iam::${org}:role${AUDIT_ROLE}"
|
||||
echo "credential_source = ${CREDSOURCE}"
|
||||
echo ""
|
||||
} >> "${AWS_MASTERS_CREDENTIALS_FILE}"
|
||||
|
||||
# Get the Organization ID to use for output paths, collecting info, etc
|
||||
org_id=$(aws --output json --profile "audit_${org}" organizations describe-organization | jq -r '.Organization.Id' )
|
||||
|
||||
echo "( $org_id )"
|
||||
ORG_ID_LIST="${ORG_ID_LIST} ${org_id}"
|
||||
|
||||
|
||||
# Build the list of all accounts in the organizations
|
||||
aws --output json --profile "audit_${org}" organizations list-accounts > "${OUTLOGS}/${STAMP}-${org_id}-account-list.json"
|
||||
# shellcheck disable=SC2002
|
||||
ORG_ACCOUNTS=$( cat "${OUTLOGS}/${STAMP}-${org_id}-account-list.json" | jq -r '.Accounts[].Id' | tr "\n" " ")
|
||||
ALL_ACCOUNTS="${ALL_ACCOUNTS} ${ORG_ACCOUNTS}"
|
||||
|
||||
# Add the Org's Accounts (including master) to the TARGETS_CREDENTIALS file
|
||||
for target in $ORG_ACCOUNTS ; do
|
||||
if echo "$target" | grep -qE "${SKIP_ACCOUNTS_REGEX}"; then
|
||||
echo " skipping account ${target} ( ${org_id} )"
|
||||
continue
|
||||
fi
|
||||
# echo " ${org_id}_${target}"
|
||||
{
|
||||
echo "[${org_id}_${target}]"
|
||||
echo "role_arn = arn:aws:iam::${target}:role${AUDIT_ROLE}"
|
||||
echo "credential_source = ${CREDSOURCE}"
|
||||
echo ""
|
||||
} >> "${AWS_TARGETS_CREDENTIALS_FILE}"
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
# Prepare credentials for standalone accounts
|
||||
if [[ "" != "${STANDALONE_ACCOUNTS}" ]] ; then
|
||||
# mkdir -p ${OUTBASE}/data/standalone/${DAYPATH} ${OUTBASE}/logs/standalone/${DAYPATH}
|
||||
for target in $STANDALONE_ACCOUNTS ; do
|
||||
echo "Preparing account ${target} ( standalone )"
|
||||
{
|
||||
echo "[standalone_${target}]"
|
||||
echo "role_arn = arn:aws:iam::${target}:role${AUDIT_ROLE}"
|
||||
echo "credential_source = ${CREDSOURCE}"
|
||||
echo ""
|
||||
} >> "${AWS_TARGETS_CREDENTIALS_FILE}"
|
||||
done
|
||||
ALL_ACCOUNTS="${ALL_ACCOUNTS} ${STANDALONE_ACCOUNTS}"
|
||||
fi
|
||||
|
||||
# grep -E '^\[' $AWS_MASTERS_CREDENTIALS_FILE $AWS_TARGETS_CREDENTIALS_FILE
|
||||
|
||||
|
||||
# Switch to Target Credential Set
|
||||
export AWS_SHARED_CREDENTIALS_FILE=${AWS_TARGETS_CREDENTIALS_FILE}
|
||||
|
||||
## visit each target account
|
||||
NUM_ACCOUNTS=$(grep -cE '^\[' "${AWS_TARGETS_CREDENTIALS_FILE}")
|
||||
echo "Launching ${CHECKGROUP} audit of ${NUM_ACCOUNTS} accounts"
|
||||
for member in $(grep -E '^\[' "${AWS_TARGETS_CREDENTIALS_FILE}" | tr -d '][') ; do
|
||||
ORG_ID=$(echo "$member" | cut -d'_' -f1)
|
||||
ACCOUNT_NUM=$(echo "$member" | cut -d'_' -f2)
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
${PARALLEL_START} "${PROWLER} -p ${member} -n -M csv -g ${CHECKGROUP} 2> ${OUTLOGS}/${STAMP}-${ORG_ID}-${ACCOUNT_NUM}-prowler-${CHECKGROUP}.log > ${OUTDATA}/${STAMP}-${ORG_ID}-${ACCOUNT_NUM}-prowler-${CHECKGROUP}.csv ; echo \"${ORG_ID}-${ACCOUNT_NUM}-prowler-${CHECKGROUP} finished\" " ${PARALLEL_START_SUFFIX}
|
||||
done
|
||||
|
||||
echo -n "waiting for parallel threads to complete - " ; date
|
||||
# shellcheck disable=SC2090
|
||||
${PARALLEL_END}
|
||||
|
||||
echo "Completed ${CHECKGROUP} audit with stamp ${STAMP}"
|
||||
|
||||
# mkdir -p ${OUTBASE}/logs/debug/${DAYPATH}
|
||||
# cp "$AWS_MASTERS_CREDENTIALS_FILE" "${OUTLOGS}/${STAMP}-master_creds.txt"
|
||||
# cp "$AWS_TARGETS_CREDENTIALS_FILE" "${OUTLOGS}/${STAMP}-target_creds.txt"
|
||||
rm "$AWS_MASTERS_CREDENTIALS_FILE" "$AWS_TARGETS_CREDENTIALS_FILE"
|
||||
212
contrib/terraform-kickstarter/data.tf
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross_claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third_party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON_INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third_party archives.
|
||||
|
||||
Copyright [2020] [© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE_2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
data "aws_iam_policy" "SecurityAudit" {
|
||||
arn = "arn:aws:iam::aws:policy/SecurityAudit"
|
||||
}
|
||||
data "aws_caller_identity" "current" {
|
||||
}
|
||||
data "aws_region" "current" {
|
||||
}
|
||||
53
contrib/terraform-kickstarter/docs/tf.md
Normal file
@@ -0,0 +1,53 @@
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 3.54 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="provider_aws"></a> [aws](#provider\_aws) | 3.55.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_cloudwatch_event_rule.prowler_check_scheduler_event](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
|
||||
| [aws_cloudwatch_event_target.run_prowler_scan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
|
||||
| [aws_codebuild_project.prowler_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |
|
||||
| [aws_iam_policy.prowler_event_trigger_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_policy.prowler_kickstarter_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_policy_attachment.prowler_event_trigger_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
|
||||
| [aws_iam_policy_attachment.prowler_kickstarter_iam_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
|
||||
| [aws_iam_role.prowler_event_trigger_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role.prowler_kick_start_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_s3_bucket.prowler_report_storage_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
|
||||
| [aws_s3_bucket_policy.prowler_report_storage_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
|
||||
| [aws_s3_bucket_public_access_block.prowler_report_storage_bucket_block_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
|
||||
| [aws_securityhub_account.securityhub_resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/securityhub_account) | resource |
|
||||
| [aws_securityhub_product_subscription.security_hub_enable_prowler_findings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/securityhub_product_subscription) | resource |
|
||||
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_iam_policy.SecurityAudit](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source |
|
||||
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| <a name="input_codebuild_timeout"></a> [codebuild\_timeout](#input\_codebuild\_timeout) | Codebuild timeout setting | `number` | `300` | no |
|
||||
| <a name="input_enable_security_hub"></a> [enable\_security\_hub](#input\_enable\_security\_hub) | Enable AWS SecurityHub. | `bool` | `true` | no |
|
||||
| <a name="input_enable_security_hub_prowler_subscription"></a> [enable\_security\_hub\_prowler\_subscription](#input\_enable\_security\_hub\_prowler\_subscription) | Enable a Prowler Subscription. | `bool` | `true` | no |
|
||||
| <a name="input_prowler_cli_options"></a> [prowler\_cli\_options](#input\_prowler\_cli\_options) | Run Prowler With The Following Command | `string` | `"_q _M json_asff _S _f us_east_1"` | no |
|
||||
| <a name="input_prowler_schedule"></a> [prowler\_schedule](#input\_prowler\_schedule) | Run Prowler based on cron schedule | `string` | `"cron(0 0 ? * * *)"` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| <a name="output_account_id"></a> [account\_id](#output\_account\_id) | TODO Move these to outputs file |
|
||||
499
contrib/terraform-kickstarter/main.tf
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross_claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third_party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON_INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third_party archives.
|
||||
|
||||
Copyright [2020] [© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE_2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Security Hub Import Commands
|
||||
|
||||
Run this to get state of SecurityHub
|
||||
|
||||
terraform import aws_securityhub_account.securityhubresource 123456789012
|
||||
|
||||
*/
|
||||
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 3.54"
|
||||
}
|
||||
}
|
||||
}
|
||||
provider "aws" {
|
||||
region = var.select_region
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "prowler_kick_start_role" {
|
||||
name = "security_baseline_kickstarter_iam_role"
|
||||
managed_policy_arns = ["${data.aws_iam_policy.SecurityAudit.arn}",
|
||||
"arn:aws:iam::aws:policy/job-function/SupportUser",
|
||||
"arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"]
|
||||
assume_role_policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action="sts:AssumeRole"
|
||||
Effect="Allow"
|
||||
Sid = "CodeBuildProwler"
|
||||
Principal = {Service="codebuild.amazonaws.com"}
|
||||
}
|
||||
]
|
||||
})
|
||||
force_detach_policies=true
|
||||
}
|
||||
resource "aws_iam_role" "prowler_event_trigger_role" {
|
||||
name = "security_baseline_kickstarter_event_trigger_iam_role"
|
||||
assume_role_policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action="sts:AssumeRole"
|
||||
Effect="Allow"
|
||||
Sid = "TriggerCodeBuild"
|
||||
Principal = {Service="events.amazonaws.com"}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
}
|
||||
resource "aws_iam_policy" "prowler_event_trigger_policy" {
|
||||
depends_on = [aws_codebuild_project.prowler_codebuild]
|
||||
name = "security_baseline_kickstarter_trigger_iam_policy"
|
||||
path = "/"
|
||||
description = "IAM Policy used to trigger the Prowler in AWS Codebuild"
|
||||
policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action = ["codebuild:StartBuild"],
|
||||
Effect = "Allow"
|
||||
Resource = aws_codebuild_project.prowler_codebuild.arn
|
||||
}]
|
||||
})
|
||||
}
|
||||
resource "aws_iam_policy_attachment" "prowler_event_trigger_policy_attach" {
|
||||
depends_on = [aws_iam_policy.prowler_event_trigger_policy]
|
||||
name = "prowler_event_trigger_policy_attach"
|
||||
roles = toset([aws_iam_role.prowler_event_trigger_role.id])
|
||||
policy_arn = aws_iam_policy.prowler_event_trigger_policy.arn
|
||||
}
|
||||
resource "aws_iam_policy" "prowler_kickstarter_iam_policy" {
|
||||
name = "security_baseline_kickstarter_iam_policy"
|
||||
path = "/"
|
||||
description = "IAM Policy used to run prowler from codebuild"
|
||||
|
||||
# Terraform's "jsonencode" function converts a
|
||||
# Terraform expression result to valid JSON syntax.
|
||||
policy = jsonencode({
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Action = [
|
||||
"logs:PutLogEvents"
|
||||
],
|
||||
Effect = "Allow"
|
||||
Resource = "arn:aws:logs:*:${data.aws_caller_identity.current.account_id}:log-group:*:log-stream:*"
|
||||
},
|
||||
{
|
||||
Action = [
|
||||
"logs:CreateLogStream",
|
||||
"logs:CreateLogGroup"
|
||||
],
|
||||
Effect = "Allow"
|
||||
Resource = "arn:aws:logs:*:${data.aws_caller_identity.current.account_id}:log-group:*"
|
||||
},
|
||||
{
|
||||
Action = ["sts:AssumeRole"],
|
||||
Effect = "Allow"
|
||||
Resource = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${aws_iam_role.prowler_kick_start_role.name}"
|
||||
},
|
||||
{
|
||||
Action = [
|
||||
"ds:ListAuthorizedApplications",
|
||||
"ec2:GetEbsEncryptionByDefault",
|
||||
"ecr:Describe*",
|
||||
"elasticfilesystem:DescribeBackupPolicy",
|
||||
"glue:GetConnections",
|
||||
"glue:GetSecurityConfiguration",
|
||||
"glue:SearchTables",
|
||||
"lambda:GetFunction",
|
||||
"s3:GetAccountPublicAccessBlock",
|
||||
"shield:DescribeProtection",
|
||||
"shield:GetSubscriptionState",
|
||||
"ssm:GetDocument",
|
||||
"support:Describe*",
|
||||
"tag:GetTagKeys"
|
||||
]
|
||||
Effect = "Allow"
|
||||
Resource = "arn:aws:glue:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:catalog"
|
||||
|
||||
},
|
||||
{
|
||||
Action = [
|
||||
"codebuild:CreateReportGroup",
|
||||
"codebuild:CreateReport",
|
||||
"codebuild:UpdateReport",
|
||||
"codebuild:BatchPutTestCases",
|
||||
"codebuild:BatchPutCodeCoverages"
|
||||
]
|
||||
Effect = "Allow"
|
||||
Resource = "arn:aws:codebuild:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:report-group/*"
|
||||
|
||||
},
|
||||
{
|
||||
Action = [ "securityhub:BatchImportFindings"]
|
||||
Effect = "Allow"
|
||||
Resource = "*"
|
||||
},
|
||||
{
|
||||
Action = [ "securityhub:GetFindings"]
|
||||
Effect = "Allow"
|
||||
Resource = "*"
|
||||
},
|
||||
{
|
||||
"Action": "codebuild:StartBuild",
|
||||
"Resource": "arn:aws:codebuild:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:project/*",
|
||||
"Effect": "Allow"
|
||||
},
|
||||
{
|
||||
"Action": ["s3:PutObject", "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:GetBucketLocation"],
|
||||
"Resource": "arn:aws:s3:::prowler-kickstart-${data.aws_region.current.name}-${data.aws_caller_identity.current.account_id}-reports/*",
|
||||
"Effect": "Allow"
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
resource "aws_iam_policy_attachment" "prowler_kickstarter_iam_policy_attach" {
|
||||
depends_on = [aws_iam_policy.prowler_kickstarter_iam_policy]
|
||||
name = "security_baseline_kickstarter_policy_attach"
|
||||
roles = toset([aws_iam_role.prowler_kick_start_role.id])
|
||||
policy_arn = aws_iam_policy.prowler_kickstarter_iam_policy.arn
|
||||
}
|
||||
resource "aws_s3_bucket" "prowler_report_storage_bucket" {
|
||||
bucket = "prowler-kickstart-${data.aws_region.current.name}-${data.aws_caller_identity.current.account_id}-reports"
|
||||
acl = "log-delivery-write"
|
||||
versioning {
|
||||
enabled = true
|
||||
}
|
||||
server_side_encryption_configuration {
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = "AES256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_policy" "prowler_report_storage_bucket_policy" {
|
||||
depends_on = [aws_s3_bucket.prowler_report_storage_bucket]
|
||||
bucket = aws_s3_bucket.prowler_report_storage_bucket.id
|
||||
policy = jsonencode({Version = "2012-10-17"
|
||||
Id = "ProwlerBucketReportPolicy"
|
||||
Statement = [
|
||||
{
|
||||
Sid = "S3ForceSSL"
|
||||
Effect = "Deny"
|
||||
Principal = "*"
|
||||
Action = "s3:*"
|
||||
Resource = ["${aws_s3_bucket.prowler_report_storage_bucket.arn}/*"]
|
||||
Condition = {
|
||||
Bool = {
|
||||
"aws:SecureTransport" = "false"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
Sid = "DenyUnEncryptedObjectUploads"
|
||||
Effect = "Deny"
|
||||
Principal = "*"
|
||||
Action = "s3:*"
|
||||
Resource = ["${aws_s3_bucket.prowler_report_storage_bucket.arn}/*"]
|
||||
Condition = {
|
||||
Null = {
|
||||
"s3:x-amz-server-side-encryption" = "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "prowler_report_storage_bucket_block_public" {
|
||||
depends_on = [aws_s3_bucket.prowler_report_storage_bucket, aws_s3_bucket_policy.prowler_report_storage_bucket_policy]
|
||||
bucket = aws_s3_bucket.prowler_report_storage_bucket.id
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
|
||||
resource "aws_codebuild_project" "prowler_codebuild" {
|
||||
name = "security_baseline_kickstarter_codebuild"
|
||||
description = "Run a Prowler Assessment with Prowler"
|
||||
build_timeout = var.codebuild_timeout
|
||||
service_role = aws_iam_role.prowler_kick_start_role.arn
|
||||
|
||||
artifacts {
|
||||
type = "NO_ARTIFACTS"
|
||||
}
|
||||
|
||||
environment {
|
||||
compute_type = "BUILD_GENERAL1_SMALL"
|
||||
image = "aws/codebuild/amazonlinux2-x86_64-standard:3.0"
|
||||
type = "LINUX_CONTAINER"
|
||||
|
||||
environment_variable {
|
||||
name = "BUCKET_REPORT"
|
||||
value = "${aws_s3_bucket.prowler_report_storage_bucket.id}"
|
||||
}
|
||||
|
||||
environment_variable {
|
||||
name = "PROWLER_OPTIONS"
|
||||
type = "PLAINTEXT"
|
||||
value = var.prowler_cli_options
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
source {
|
||||
type = "NO_SOURCE"
|
||||
buildspec = "${file("prowler_build_spec.yml")}"
|
||||
}
|
||||
|
||||
tags = {
|
||||
Environment = "Prowler KickStarter"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
resource "aws_securityhub_account" "securityhub_resource" {
|
||||
}
|
||||
|
||||
resource "aws_securityhub_product_subscription" "security_hub_enable_prowler_findings" {
|
||||
depends_on = [aws_securityhub_account.securityhub_resource]
|
||||
//arn:aws:securityhub:<REGION>::product/prowler/prowler
|
||||
product_arn = "arn:aws:securityhub:${data.aws_region.current.name}::product/prowler/prowler"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_rule" "prowler_check_scheduler_event" {
|
||||
|
||||
name = "security_baseline_kickstarter_event_cron"
|
||||
description = "Run Prowler every night"
|
||||
schedule_expression = var.prowler_schedule
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_event_target" "run_prowler_scan" {
|
||||
|
||||
arn = aws_codebuild_project.prowler_codebuild.arn
|
||||
rule = aws_cloudwatch_event_rule.prowler_check_scheduler_event.name
|
||||
role_arn = aws_iam_role.prowler_event_trigger_role.arn
|
||||
|
||||
}
|
||||
209
contrib/terraform-kickstarter/outputs.tf
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross_claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third_party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON_INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third_party archives.
|
||||
|
||||
Copyright [2020] [© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE_2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
output "account_id" {
|
||||
value = data.aws_caller_identity.current.account_id
|
||||
}
|
||||
24
contrib/terraform-kickstarter/prowler_build_spec.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
version: 0.2
|
||||
phases:
|
||||
install:
|
||||
runtime-versions:
|
||||
python: 3.8
|
||||
commands:
|
||||
- echo "Installing Prowler and dependencies..."
|
||||
- pip3 install detect-secrets
|
||||
- yum -y install jq
|
||||
- curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||
- unzip awscliv2.zip
|
||||
- ./aws/install
|
||||
- git clone https://github.com/prowler-cloud/prowler
|
||||
- cd prowler
|
||||
|
||||
build:
|
||||
commands:
|
||||
- echo "Running Prowler as ./prowler $PROWLER_OPTIONS"
|
||||
- ./prowler $PROWLER_OPTIONS || true
|
||||
post_build:
|
||||
commands:
|
||||
- echo "Scan Complete"
|
||||
- aws s3 cp --sse AES256 output/ s3://$BUCKET_REPORT/ --recursive
|
||||
- echo "Done!"
|
||||
93
contrib/terraform-kickstarter/readme.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Install Security Baseline Kickstarter with Prowler
|
||||
|
||||
## Introduction
|
||||
|
||||
The following demonstartes how to quickly install the resources necessary to perform a security baseline using Prowler. The speed is based on the prebuilt terraform module that can configure all the resources necessuary to run Prowler with the findings being sent to AWS Security Hub.
|
||||
|
||||
## Install
|
||||
|
||||
Installing Prowler with Terraform is simple and can be completed in under 1 minute.
|
||||
|
||||
- Start AWS CloudShell
|
||||
- Run the following commands to install Terraform and clone the Prowler git repo
|
||||
```
|
||||
git clone https://github.com/prowler-cloud/prowler.git
|
||||
cd prowler
|
||||
sudo yum install -y yum-utils
|
||||
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
|
||||
sudo yum -y install terraform
|
||||
cd util/terraform-kickstarter
|
||||
```
|
||||
- Issue a `terraform init`
|
||||
|
||||
- Issue a `terraform apply`
|
||||
|
||||

|
||||
|
||||
- It is likely an error will return related to the SecurityHub subscription. This appears to be Terraform related and you can validate the configuration by navigating to the SecurityHub console. Click Integreations and search for Prowler. Take note of the green check where it says *Accepting findings*
|
||||
|
||||

|
||||
|
||||
|
||||
Thats it! Install is now complete. The resources include a Cloudwatch event that will trigger the AWS Codebuild to run daily at 00:00 GMT. If you'd like to run an assessment after the deployment then simply navigate to the Codebuild console and start the job manually.
|
||||
|
||||
## Terraform Resources
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 3.54 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| <a name="provider_aws"></a> [aws](#provider\_aws) | 3.56.0 |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_cloudwatch_event_rule.prowler_check_scheduler_event](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
|
||||
| [aws_cloudwatch_event_target.run_prowler_scan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
|
||||
| [aws_codebuild_project.prowler_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |
|
||||
| [aws_iam_policy.prowler_event_trigger_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_policy.prowler_kickstarter_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
|
||||
| [aws_iam_policy_attachment.prowler_event_trigger_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
|
||||
| [aws_iam_policy_attachment.prowler_kickstarter_iam_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
|
||||
| [aws_iam_role.prowler_event_trigger_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role.prowler_kick_start_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_s3_bucket.prowler_report_storage_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
|
||||
| [aws_s3_bucket_policy.prowler_report_storage_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
|
||||
| [aws_s3_bucket_public_access_block.prowler_report_storage_bucket_block_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
|
||||
| [aws_securityhub_account.securityhub_resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/securityhub_account) | resource |
|
||||
| [aws_securityhub_product_subscription.security_hub_enable_prowler_findings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/securityhub_product_subscription) | resource |
|
||||
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_iam_policy.SecurityAudit](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source |
|
||||
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| <a name="input_codebuild_timeout"></a> [codebuild\_timeout](#input\_codebuild\_timeout) | Codebuild timeout setting | `number` | `300` | no |
|
||||
| <a name="input_enable_security_hub"></a> [enable\_security\_hub](#input\_enable\_security\_hub) | Enable AWS SecurityHub. | `bool` | `true` | no |
|
||||
| <a name="input_enable_security_hub_prowler_subscription"></a> [enable\_security\_hub\_prowler\_subscription](#input\_enable\_security\_hub\_prowler\_subscription) | Enable a Prowler Subscription. | `bool` | `true` | no |
|
||||
| <a name="input_prowler_cli_options"></a> [prowler\_cli\_options](#input\_prowler\_cli\_options) | Run Prowler With The Following Command | `string` | `"-q -M json-asff -S -f us-east-1"` | no |
|
||||
| <a name="input_prowler_schedule"></a> [prowler\_schedule](#input\_prowler\_schedule) | Run Prowler based on cron schedule | `string` | `"cron(0 0 ? * * *)"` | no |
|
||||
| <a name="input_select_region"></a> [select\_region](#input\_select\_region) | Uses the following AWS Region. | `string` | `"us-east-1"` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| <a name="output_account_id"></a> [account\_id](#output\_account\_id) | n/a |
|
||||
|
||||
## Kickoff Prowler Assessment From Install to Assessment Demo (Link to YouTube)
|
||||
|
||||
[](https://www.youtube.com/watch?v=ShhzIArO8X0 "Prowler Install")
|
||||
9
contrib/terraform-kickstarter/tf_install.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
#AMZN-Linux Terraform Install Script
|
||||
git clone https://github.com/singergs/prowler.git
|
||||
git fetch
|
||||
cd prowler
|
||||
git checkout -t origin/terraform-kickstart
|
||||
sudo yum install -y yum-utils
|
||||
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
|
||||
sudo yum -y install terraform
|
||||
251
contrib/terraform-kickstarter/variables.tf
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non_exclusive, no_charge, royalty_free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross_claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third_party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON_INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third_party archives.
|
||||
|
||||
Copyright [2020] [© 2020 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE_2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Security Hub Import Commands
|
||||
|
||||
Run this to get state of SecurityHub
|
||||
|
||||
terraform import aws_securityhub_account.securityhubresource 123456789012
|
||||
|
||||
*/
|
||||
|
||||
variable "select_region" {
|
||||
description = "Uses the following AWS Region."
|
||||
type = string
|
||||
default = "us-east-1"
|
||||
}
|
||||
|
||||
variable "enable_security_hub" {
|
||||
description = "Enable AWS SecurityHub."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_security_hub_prowler_subscription" {
|
||||
description = "Enable a Prowler Subscription."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "prowler_cli_options" {
|
||||
description = "Run Prowler With The Following Command"
|
||||
type = string
|
||||
default = "-q -M json-asff -S -f us-east-1"
|
||||
}
|
||||
|
||||
variable "prowler_schedule"{
|
||||
description = "Run Prowler based on cron schedule"
|
||||
default="cron(0 0 ? * * *)"
|
||||
type=string
|
||||
|
||||
}
|
||||
|
||||
variable "codebuild_timeout" {
|
||||
description = "Codebuild timeout setting"
|
||||
default = 300
|
||||
type=number
|
||||
}
|
||||
115
contrib/wazuh/README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Prowler integration with Wazuh (DRAFT)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Description](#description)
|
||||
- [Features](#features)
|
||||
- [Requirements](#requirements)
|
||||
- [Integration steps](#integration-steps)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Thanks](#thanks)
|
||||
- [License](#license)
|
||||
|
||||
## Description
|
||||
|
||||
Prowler integration with WAZUH using a python wrapper. Due to the wrapper limitations, this integration can be considered as a proof of concept at this time.
|
||||
|
||||
## Features
|
||||
|
||||
Wazuh, using a wodle, runs Prowler every certain time and stores alerts (failed checks) using JSON output which Wazuh processes and sends to Elastic Search to be queried from Kibana.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. Latest AWS-CLI client (`pip install awscli`). If you have it already installed, make sure you are using the latest version, upgrade it: `pip install awscli --upgrade`.
|
||||
2. Also `jq` is needed (`pip install jq`).
|
||||
|
||||
Remember, you must have AWS-CLI credentials already configured in the same instance running Wazuh (run `aws configure` if needed). In this DRAFT I'm using `/root/.aws/credentials` file with [default] as AWS-CLI profile and access keys but you can use assume role configuration as well. For the moment instance profile is not supported in this wrapper.
|
||||
|
||||
It may work in previous versions of Wazuh, but this document and integration was tested on Wazuh 3.7.1. So to have a Wazuh running installation is obviously required.
|
||||
|
||||
## Integration steps
|
||||
|
||||
Add Prowler to Wazuh's integrations:
|
||||
```
|
||||
cd /var/ossec/integrations/
|
||||
git clone https://github.com/toniblyx/prowler
|
||||
```
|
||||
Copy `prowler-wrapper.py` to integrations folder:
|
||||
|
||||
```
|
||||
cp /var/ossec/integrations/prowler/integrations/prowler-wrapper.py /var/ossec/integrations/prowler-wrapper.py
|
||||
```
|
||||
Then make sure it is executable:
|
||||
```
|
||||
chmod +x /var/ossec/integrations/prowler-wrapper.py
|
||||
```
|
||||
Run Prowler wrapper manually to make sure it works fine, use `--debug 1` or `--debug 2`):
|
||||
```
|
||||
/var/ossec/integrations/prowler-wrapper.py --aws_profile default --aws_account_alias default --debug 2
|
||||
```
|
||||
|
||||
Copy rules file to its location:
|
||||
|
||||
```
|
||||
cp /var/ossec/integrations/prowler/integrations/prowler_rules.xml /var/ossec/etc/rules/prowler_rules.xml
|
||||
```
|
||||
|
||||
Edit `/var/ossec/etc/ossec.conf` and add the following wodle configuration. Remember that here `timeout 21600 seconds` is 6 hours, just to allow Prowler runs completely in case of a large account. The interval recommended is 1d:
|
||||
```xml
|
||||
<wodle name="command">
|
||||
<disabled>no</disabled>
|
||||
<tag>aws-prowler: account1</tag>
|
||||
<command>/var/ossec/integrations/prowler-wrapper.py --aws_profile default --aws_account_alias default</command>
|
||||
<interval>1d</interval>
|
||||
<ignore_output>no</ignore_output>
|
||||
<run_on_start>no</run_on_start>
|
||||
<timeout>21600</timeout>
|
||||
</wodle>
|
||||
```
|
||||
To check multiple AWS accounts, add a wodle per account.
|
||||
|
||||
Now restart `wazuh-manager` and look at `/var/ossec/logs/alerts/alerts.json`, eventually you should see FAIL checks detected by Prowler, then you will find them using Kibana. Some Kibana search examples are:
|
||||
```
|
||||
data.integration:"prowler" and data.prowler.status:"Fail"
|
||||
data.integration:"prowler" AND rule.level >= 5
|
||||
data.integration:"prowler" AND rule.level : 7 or 9
|
||||
```
|
||||
|
||||
Adjust the level range to what alerts you want to include, as alerts, Elastic Search only gets fail messages (7 and 9).
|
||||
|
||||
1 - pass
|
||||
3 - info
|
||||
5 - error
|
||||
7 - fail: not scored
|
||||
9 - fail: scored
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
To make sure rules are working fine, run `/var/ossec/bin/ossec-logtest` and copy/paste this sample JSON:
|
||||
|
||||
```json
|
||||
{"prowler":{"Timestamp":"2018-11-29T03:15:50Z","Region":"us-east-1","Profile":"default","Account Number”:”1234567890”,”Control":"[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)","Message":"No CloudWatch group found for CloudTrail events","Status":"Fail","Scored":"Scored","Level":"Level 1","Control ID":"3.4"}, "integration": "prowler"}
|
||||
```
|
||||
You must see 3 phases goin on.
|
||||
|
||||
To check if there is any error you can enable the debug mode of `modulesd` setting the `wazuh_modules.debug=0` variable to 2 in `/var/ossec/etc/internal_options.conf` file. Restart wazun-manager and errors should appear in the `/var/ossec/logs/ossec.log` file.
|
||||
|
||||
## Thanks
|
||||
|
||||
To Jeremy Phillips <jeremy@uranusbytes.com>, who wrote the initial rules file and wrapper and helped me to understand how it works and debug it.
|
||||
|
||||
To [Marta Gomez](https://github.com/mgmacias95) and the [Wazuh](https://www.wazuh.com) team for their support to debug this integration and make it work properly. Their job on Wazuh and willingness to help is invaluable.
|
||||
|
||||
## License
|
||||
|
||||
All CIS based checks in the checks folder are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License.
|
||||
The link to the license terms can be found at
|
||||
<https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode>
|
||||
Any other piece of code is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>
|
||||
|
||||
NOTE: If you are interested in using Prowler for commercial purposes remember that due to the CC4.0 license “The distributors or partners that are interested and using Prowler would need to enroll as CIS SecureSuite Members to incorporate this product, which includes references to CIS resources, in their offering.". Information about CIS pricing for vendors here: <https://www.cisecurity.org/cis-securesuite/pricing-and-categories/product-vendor/>
|
||||
|
||||
**I'm not related anyhow with CIS organization, I just write and maintain Prowler to help companies over the world to make their cloud infrastructure more secure.**
|
||||
|
||||
If you want to contact me visit <https://blyx.com/contact>
|
||||
242
contrib/wazuh/prowler-wrapper.py
Normal file
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Authored by Jeremy Phillips <jeremy@uranusbytes.com>
|
||||
# Copyright: Apache License 2.0
|
||||
#
|
||||
# Wrapper around prowler script to parse results and forward to Wazuh
|
||||
# Prowler - https://github.com/toniblyx/prowler
|
||||
#
|
||||
# TODO: Add ability to disable different groups (EXTRA, etc...
|
||||
# TODO: Allow to disable individual checks
|
||||
# TODO: Remove all the commented out stuff
|
||||
#
|
||||
# Error Codes:
|
||||
# 1 - Unknown
|
||||
# 2 - SIGINT
|
||||
# 3 - Error output from execution of Prowler
|
||||
# 4 - Output row is invalid json
|
||||
# 5 - Wazuh must be running
|
||||
# 6 - Error sending to socket
|
||||
|
||||
|
||||
import signal
|
||||
import sys
|
||||
import socket
|
||||
import argparse
|
||||
import subprocess
|
||||
import json
|
||||
from datetime import datetime
|
||||
import os
|
||||
import re
|
||||
|
||||
################################################################################
|
||||
# Constants
|
||||
################################################################################
|
||||
WAZUH_PATH = open('/etc/ossec-init.conf').readline().split('"')[1]
|
||||
DEBUG_LEVEL = 0 # Enable/disable debug mode
|
||||
PATH_TO_PROWLER = '{0}/integrations/prowler'.format(WAZUH_PATH) # No trailing slash
|
||||
TEMPLATE_CHECK = '''
|
||||
{{
|
||||
"integration": "prowler",
|
||||
"prowler": {0}
|
||||
}}
|
||||
'''
|
||||
TEMPLATE_MSG = '1:Wazuh-Prowler:{0}'
|
||||
TEMPLATE_ERROR = '''{{
|
||||
"aws_account_id": {aws_account_id},
|
||||
"aws_profile": "{aws_profile}",
|
||||
"prowler_error": "{prowler_error}",
|
||||
"prowler_version": "{prowler_version}",
|
||||
"timestamp": "{timestamp}",
|
||||
"status": "Error"
|
||||
}}
|
||||
'''
|
||||
WAZUH_QUEUE = '{0}/queue/ossec/queue'.format(WAZUH_PATH)
|
||||
FIELD_REMAP = {
|
||||
"Profile": "aws_profile",
|
||||
"Control": "control",
|
||||
"Account Number": "aws_account_id",
|
||||
"Level": "level",
|
||||
"Account Alias": "aws_account_alias",
|
||||
"Timestamp": "timestamp",
|
||||
"Region": "region",
|
||||
"Control ID": "control_id",
|
||||
"Status": "status",
|
||||
"Scored": "scored",
|
||||
"Message": "message"
|
||||
}
|
||||
CHECKS_FILES_TO_IGNORE = [
|
||||
'check_sample'
|
||||
]
|
||||
|
||||
|
||||
################################################################################
|
||||
# Functions
|
||||
################################################################################
|
||||
def _send_msg(msg):
|
||||
try:
|
||||
_json_msg = json.dumps(_reformat_msg(msg))
|
||||
_debug("Sending Msg: {0}".format(_json_msg), 3)
|
||||
_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
||||
_socket.connect(WAZUH_QUEUE)
|
||||
_socket.send(TEMPLATE_MSG.format(_json_msg).encode())
|
||||
_socket.close()
|
||||
except socket.error as e:
|
||||
if e.errno == 111:
|
||||
print('ERROR: Wazuh must be running.')
|
||||
sys.exit(5)
|
||||
else:
|
||||
print("ERROR: Error sending message to wazuh: {}".format(e))
|
||||
sys.exit(6)
|
||||
except Exception as e:
|
||||
print("ERROR: Error sending message to wazuh: {}".format(e))
|
||||
sys.exit(6)
|
||||
return
|
||||
|
||||
|
||||
def _handler(signal, frame):
|
||||
print("ERROR: SIGINT received.")
|
||||
sys.exit(12)
|
||||
|
||||
|
||||
def _debug(msg, msg_level):
|
||||
if DEBUG_LEVEL >= msg_level:
|
||||
print('DEBUG-{level}: {debug_msg}'.format(level=msg_level, debug_msg=msg))
|
||||
|
||||
|
||||
def _get_script_arguments():
|
||||
_parser = argparse.ArgumentParser(usage="usage: %(prog)s [options]",
|
||||
description="Wazuh wodle for evaluating AWS security configuration",
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
_parser.add_argument('-c', '--aws_account_id', dest='aws_account_id',
|
||||
help='AWS Account ID for logs',
|
||||
required=False)
|
||||
_parser.add_argument('-d', '--debug', action='store', dest='debug', default=0, help='Enable debug')
|
||||
_parser.add_argument('-p', '--aws_profile', dest='aws_profile', help='The name of credential profile to use',
|
||||
default=None)
|
||||
_parser.add_argument('-n', '--aws_account_alias', dest='aws_account_alias',
|
||||
help='AWS Account ID Alias', default='')
|
||||
_parser.add_argument('-e', '--skip_on_error', action='store_false', dest='skip_on_error',
|
||||
help='If check output is invalid json, error out instead of skipping the check', default=True)
|
||||
return _parser.parse_args()
|
||||
|
||||
|
||||
def _run_prowler(prowler_args):
|
||||
_debug('Running prowler with args: {0}'.format(prowler_args), 1)
|
||||
_prowler_command = '{prowler}/prowler {args}'.format(prowler=PATH_TO_PROWLER, args=prowler_args)
|
||||
_debug('Running command: {0}'.format(_prowler_command), 2)
|
||||
_process = subprocess.Popen(_prowler_command, stdout=subprocess.PIPE, shell=True)
|
||||
_output, _error = _process.communicate()
|
||||
_debug('Raw prowler output: {0}'.format(_output), 3)
|
||||
_debug('Raw prowler error: {0}'.format(_error), 3)
|
||||
if _error is not None:
|
||||
_debug('PROWLER ERROR: {0}'.format(_error), 1)
|
||||
exit(3)
|
||||
return _output
|
||||
|
||||
|
||||
def _get_prowler_version(options):
|
||||
_debug('+++ Get Prowler Version', 1)
|
||||
# Execute prowler, but only display the version and immediately exit
|
||||
return _run_prowler('-p {0} -V'.format(options.aws_profile)).rstrip()
|
||||
|
||||
|
||||
def _get_prowler_results(options, prowler_check):
|
||||
_debug('+++ Get Prowler Results - {check}'.format(check=prowler_check), 1)
|
||||
# Execute prowler with all checks
|
||||
# -b = disable banner
|
||||
# -p = credential profile
|
||||
# -M = output json
|
||||
|
||||
return _run_prowler('-b -c {check} -p {aws_profile} -M json'.format(check=prowler_check,
|
||||
aws_profile=options.aws_profile))
|
||||
|
||||
def _get_prowler_checks():
|
||||
_prowler_checks = []
|
||||
for _directory_path, _directories, _files in os.walk('{path}/checks'.format(path=PATH_TO_PROWLER)):
|
||||
_debug('Checking in : {}'.format(_directory_path), 3)
|
||||
for _file in _files:
|
||||
if _file in CHECKS_FILES_TO_IGNORE:
|
||||
_debug('Ignoring check - {}'.format(_directory_path, _file), 3)
|
||||
elif re.match("check\d+", _file):
|
||||
_prowler_checks.append(_file)
|
||||
elif re.match("check_extra(\d+)", _file):
|
||||
_prowler_checks.append(_file[6:])
|
||||
else:
|
||||
_debug('Unknown check file type- {}'.format(_directory_path, _file), 3)
|
||||
return _prowler_checks
|
||||
|
||||
|
||||
def _send_prowler_results(prowler_results, _prowler_version, options):
|
||||
_debug('+++ Send Prowler Results', 1)
|
||||
for _check_result in prowler_results.splitlines():
|
||||
# Empty row
|
||||
if len(_check_result) < 1:
|
||||
continue
|
||||
# Something failed during prowler check
|
||||
elif _check_result[:17] == 'An error occurred':
|
||||
_debug('ERROR MSG --- {0}'.format(_check_result), 2)
|
||||
_temp_msg = TEMPLATE_ERROR.format(
|
||||
aws_account_id=options.aws_account_id,
|
||||
aws_profile=options.aws_profile,
|
||||
prowler_error=_check_result.replace('"', '\"'),
|
||||
prowler_version=_prowler_version,
|
||||
timestamp=datetime.now().isoformat()
|
||||
)
|
||||
_error_msg = json.loads(TEMPLATE_CHECK.format(_temp_msg))
|
||||
_send_msg(_error_msg)
|
||||
continue
|
||||
try:
|
||||
_debug('RESULT MSG --- {0}'.format(_check_result), 2)
|
||||
_check_result = json.loads(TEMPLATE_CHECK.format(_check_result))
|
||||
except:
|
||||
_debug('INVALID JSON --- {0}'.format(TEMPLATE_CHECK.format(_check_result)), 1)
|
||||
if not options.skip_on_error:
|
||||
exit(4)
|
||||
_check_result['prowler']['prowler_version'] = _prowler_version
|
||||
_check_result['prowler']['aws_account_alias'] = options.aws_account_alias
|
||||
_send_msg(_check_result)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _reformat_msg(msg):
|
||||
for field in FIELD_REMAP:
|
||||
if field in msg['prowler']:
|
||||
msg['prowler'][FIELD_REMAP[field]] = msg['prowler'][field]
|
||||
del msg['prowler'][field]
|
||||
return msg
|
||||
|
||||
|
||||
# Main
|
||||
###############################################################################
|
||||
def main(argv):
|
||||
_debug('+++ Begin script', 1)
|
||||
# Parse arguments
|
||||
_options = _get_script_arguments()
|
||||
|
||||
if int(_options.debug) > 0:
|
||||
global DEBUG_LEVEL
|
||||
DEBUG_LEVEL = int(_options.debug)
|
||||
_debug('+++ Debug mode on - Level: {debug}'.format(debug=_options.debug), 1)
|
||||
|
||||
_prowler_version = _get_prowler_version(_options)
|
||||
_prowler_checks = _get_prowler_checks()
|
||||
for _check in _prowler_checks:
|
||||
_prowler_results = _get_prowler_results(_options, _check)
|
||||
_send_prowler_results(_prowler_results, _prowler_version, _options)
|
||||
_debug('+++ Finished script', 1)
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
_debug('Args: {args}'.format(args=str(sys.argv)), 2)
|
||||
signal.signal(signal.SIGINT, _handler)
|
||||
main(sys.argv[1:])
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
print("Unknown error: {}".format(e))
|
||||
if DEBUG_LEVEL > 0:
|
||||
raise
|
||||
sys.exit(1)
|
||||
45
contrib/wazuh/prowler_rules.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<!--
|
||||
Rules for parsing Prowler output
|
||||
Authored by Jeremy Phillips <jeremy@uranusbytes.com>
|
||||
Copyright: Apache License 2.0
|
||||
ID: 110000-110009
|
||||
Prowler - https://github.com/toniblyx/prowler
|
||||
-->
|
||||
|
||||
<group name="local,amazon,prowler,">
|
||||
<!-- Filter 1: Only prowler events -->
|
||||
<rule id="110001" level="0">
|
||||
<field name="integration">prowler</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
<!-- Check Result: Pass -->
|
||||
<rule id="110002" level="1">
|
||||
<if_sid>110001</if_sid>
|
||||
<field name="prowler.status">Pass</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
<!-- Check Result: Info -->
|
||||
<rule id="110003" level="3">
|
||||
<if_sid>110001</if_sid>
|
||||
<field name="prowler.status">Info</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
<!-- Check Result: Error -->
|
||||
<rule id="110004" level="5">
|
||||
<if_sid>110001</if_sid>
|
||||
<field name="prowler.status">Error</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
<!-- Check Result: Fail, Scored -->
|
||||
<rule id="110005" level="9">
|
||||
<if_sid>110001</if_sid>
|
||||
<field name="prowler.status">Fail</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
<!-- Check Result: Fail, Not Scored -->
|
||||
<rule id="110006" level="7">
|
||||
<if_sid>110005</if_sid>
|
||||
<field name="prowler.scored">Not Scored</field>
|
||||
<description>Prowler Check Result: $(prowler.status) - Control $(prowler.control_id)</description>
|
||||
</rule>
|
||||
</group>
|
||||