--- AWSTemplateFormatVersion: 2010-09-09 Description: Creates a CodeBuild project to audit an AWS account with Prowler Version 2 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, use -f to filter specific regions, -c for specific checks, -s for specific services, for SecurityHub integration use "-f shub_region -S", for more options see -h. For a complete assessment leave this empty.' Type: String # Prowler command below runs a set of checks, configure it base on your needs, no options will run all regions all checks. Default: -f eu-west-1 -s s3 iam ec2 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: - account:Get* - appstream:Describe* - codeartifact:List* - codebuild:BatchGet* - ds:Get* - ds:Describe* - ds:List* - ec2:GetEbsEncryptionByDefault - ecr:Describe* - elasticfilesystem:DescribeBackupPolicy - glue:GetConnections - glue:GetSecurityConfiguration* - glue:SearchTables - lambda:GetFunction* - macie2:GetMacieSession - s3:GetAccountPublicAccessBlock - s3:GetPublicAccessBlock - shield:DescribeProtection - shield:GetSubscriptionState - securityhub:BatchImportFindings - securityhub:GetFindings - ssm:GetDocument - support:Describe* - tag:GetTagKeys Effect: Allow Resource: '*' - PolicyName: ProwlerAdditionsApiGW PolicyDocument: Version: '2012-10-17' Statement: - Action: - apigateway:GET Effect: Allow Resource: 'arn:aws:apigateway:*::/restapis/*' - 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: Type: NO_SOURCE BuildSpec: | version: 0.2 phases: install: runtime-versions: python: 3.9 commands: - echo "Installing Prowler..." - pip3 install prowler 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!" # Currently not supported in Version 3 # 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