diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..b7685ea666
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1 @@
+By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
diff --git a/README.md b/README.md
index 3405705be3..6638da32e4 100644
--- a/README.md
+++ b/README.md
@@ -314,6 +314,7 @@ Instead of using default policy SecurityAudit for the account you use for checks
"directconnect:describe*",
"dynamodb:listtables",
"ec2:describe*",
+ "ec2:GetEbsEncryptionByDefault",
"ecr:describe*",
"ecs:describe*",
"ecs:list*",
@@ -343,6 +344,11 @@ Instead of using default policy SecurityAudit for the account you use for checks
"rds:downloaddblogfileportion",
"rds:listtagsforresource",
"redshift:describe*",
+ "route53domains:getdomaindetail",
+ "route53domains:getoperationdetail",
+ "route53domains:listdomains",
+ "route53domains:listoperations",
+ "route53domains:listtagsfordomain",
"route53:getchange",
"route53:getcheckeripranges",
"route53:getgeolocation",
@@ -361,12 +367,8 @@ Instead of using default policy SecurityAudit for the account you use for checks
"route53:listreusabledelegationsets",
"route53:listtagsforresource",
"route53:listtagsforresources",
- "route53domains:getdomaindetail",
- "route53domains:getoperationdetail",
- "route53domains:listdomains",
- "route53domains:listoperations",
- "route53domains:listtagsfordomain",
"s3:getbucket*",
+ "s3:GetEncryptionConfiguration",
"s3:getlifecycleconfiguration",
"s3:getobjectacl",
"s3:getobjectversionacl",
diff --git a/checks/check31 b/checks/check31
index 13a11eb1e4..8a8d1329cd 100644
--- a/checks/check31
+++ b/checks/check31
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/MyCloudTrailLG \
+# --filter-name AWSAuthorizationFailures \
+# --filter-pattern '{ $.errorCode = "*UnauthorizedOperation" || $.errorCode = "AccessDenied*" }' \
+# --metric-transformations metricName=AuthorizationFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name "Authorization Failures" \
+# --alarm-description "Alarm triggered when unauthorized API calls are made" \
+# --metric-name AuthorizationFailureCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check31="3.1,3.01"
CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)"
diff --git a/checks/check310 b/checks/check310
index 3c1e1d1124..77f4b5a3ce 100644
--- a/checks/check310
+++ b/checks/check310
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name SecurityGroupConfigChanges \
+# --filter-pattern '{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) }' \
+# --metric-transformations metricName=SecurityGroupEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name SecurityGroupConfigChangesAlarm \
+# --alarm-description "Triggered by AWS security group(s) config changes." \
+# --metric-name SecurityGroupEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check310="3.10"
CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check310="LEVEL2"
CHECK_ALTERNATE_check310="check310"
check310(){
- check3x '\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup'
+ check3x '\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup'
}
diff --git a/checks/check311 b/checks/check311
index 12aec273f4..b69fc75a2d 100644
--- a/checks/check311
+++ b/checks/check311
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name NetworkACLConfigChanges \
+# --filter-pattern '{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }' \
+# --metric-transformations metricName=NetworkAclEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name NetworkACLConfigChangesAlarm \
+# --alarm-description "Triggered by AWS Network ACL(s) config changes." \
+# --metric-name NetworkAclEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check311="3.11"
CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check311="LEVEL2"
CHECK_ALTERNATE_check311="check311"
check311(){
- check3x '\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation'
+ check3x '\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation'
}
diff --git a/checks/check312 b/checks/check312
index 0bf516b693..49e1462e3e 100644
--- a/checks/check312
+++ b/checks/check312
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name VPCGatewayConfigChanges \
+# --filter-pattern '{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }' \
+# --metric-transformations metricName=GatewayEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name VPCGatewayConfigChangesAlarm \
+# --alarm-description "Triggered by VPC Customer/Internet Gateway changes." \
+# --metric-name GatewayEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check312="3.12"
CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check312="LEVEL1"
CHECK_ALTERNATE_check312="check312"
check312(){
- check3x '\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway'
+ check3x '\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway'
}
diff --git a/checks/check313 b/checks/check313
index ca619ecc72..a6a81edc01 100644
--- a/checks/check313
+++ b/checks/check313
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name RouteTableConfigChanges \
+# --filter-pattern '{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }' \
+# --metric-transformations metricName=RouteTableEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name RouteTableConfigChangesAlarm \
+# --alarm-description "Triggered by AWS Route Table config changes." \
+# --metric-name RouteTableEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check313="3.13"
CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check313="LEVEL1"
CHECK_ALTERNATE_check313="check313"
check313(){
- check3x '\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable'
+ check3x '\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable'
}
diff --git a/checks/check314 b/checks/check314
index 6c29c94632..3a6c9d7d27 100644
--- a/checks/check314
+++ b/checks/check314
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name VPCNetworkConfigChanges \
+# --filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }' \
+# --metric-transformations metricName=VpcEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name VPCNetworkConfigChangesAlarm \
+# --alarm-description "Triggered by AWS VPC(s) environment config changes." \
+# --metric-name VpcEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check314="3.14"
CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check314="LEVEL1"
CHECK_ALTERNATE_check314="check314"
check314(){
- check3x '\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink'
+ check3x '\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink'
}
diff --git a/checks/check32 b/checks/check32
index e13b18dd57..83779842df 100644
--- a/checks/check32
+++ b/checks/check32
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name ConsoleSignInWithoutMfaCount \
+# --filter-pattern '{ $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed != "Yes" }' \
+# --metric-transformations metricName=ConsoleSignInWithoutMfaCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name ConsoleSignInWithoutMfaAlarm \
+# --alarm-description "Triggered by sign-in requests made without MFA." \
+# --metric-name ConsoleSignInWithoutMfaCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check32="3.2,3.02"
CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)"
diff --git a/checks/check33 b/checks/check33
index b6825566c0..00c6d7dd65 100644
--- a/checks/check33
+++ b/checks/check33
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name RootAccountUsage \
+# --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
+# --metric-transformations metricName=RootAccountUsageEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 \
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name RootAccountUsageAlarm \
+# --alarm-description "Triggered by AWS Root Account usage." \
+# --metric-name RootAccountUsageEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check33="3.3,3.03"
CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)"
diff --git a/checks/check34 b/checks/check34
index 4eaf345cd6..e4751c79e1 100644
--- a/checks/check34
+++ b/checks/check34
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name IAMAuthConfigChanges \
+# --filter-pattern '{ ($.eventName = DeleteGroupPolicy) || ($.eventName = DeleteRolePolicy) || ($.eventName = DeleteUserPolicy) || ($.eventName = PutGroupPolicy) || ($.eventName = PutRolePolicy) || ($.eventName = PutUserPolicy) || ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = CreatePolicyVersion) || ($.eventName = DeletePolicyVersion) || ($.eventName = AttachRolePolicy) || ($.eventName = DetachRolePolicy) || ($.eventName = AttachUserPolicy) || ($.eventName = DetachUserPolicy) || ($.eventName = AttachGroupPolicy) || ($.eventName = DetachGroupPolicy) }' \
+# --metric-transformations metricName=IAMPolicyEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name IAMAuthorizationActivityAlarm \
+# --alarm-description "Triggered by AWS IAM authorization config changes." \
+# --metric-name IAMPolicyEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check34="3.4,3.04"
CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check34="LEVEL1"
CHECK_ALTERNATE_check304="check34"
check34(){
- check3x '\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy'
+ check3x '\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy'
}
diff --git a/checks/check35 b/checks/check35
index 63ba2243cb..b8b4c6cf7f 100644
--- a/checks/check35
+++ b/checks/check35
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/MyCloudTrailLG \
+# --filter-name AWSCloudTrailChanges \
+# --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' \
+# --metric-transformations metricName=CloudTrailEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name "CloudTrail Changes" \
+# --alarm-description "Triggered by AWS CloudTrail configuration changes." \
+# --metric-name CloudTrailEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check35="3.5,3.05"
CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check35="LEVEL1"
CHECK_ALTERNATE_check305="check35"
check35(){
- check3x '\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging'
+ check3x '\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging'
}
diff --git a/checks/check36 b/checks/check36
index 8fc6d86f5e..699739d89a 100644
--- a/checks/check36
+++ b/checks/check36
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/MyCloudTrailLG \
+# --filter-name AWSConsoleSignInFailures \
+# --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed authentication") }' \
+# --metric-transformations metricName=ConsoleSigninFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name "Console Sign-in Failures" \
+# --alarm-description "AWS Management Console Sign-in Failure Alarm." \
+# --metric-name ConsoleSigninFailureCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 3 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check36="3.6,3.06"
CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)"
diff --git a/checks/check37 b/checks/check37
index 44e671135e..c0390bc97b 100644
--- a/checks/check37
+++ b/checks/check37
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name AWSCMKChanges \
+# --filter-pattern '{ ($.eventSource = kms.amazonaws.com) && (($.eventName = DisableKey) || ($.eventName = ScheduleKeyDeletion)) }' \
+# --metric-transformations metricName=CMKEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name AWSCMKChangesAlarm \
+# --alarm-description "Triggered by AWS CMK changes." \
+# --metric-name CMKEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check37="3.7,3.07"
CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)"
diff --git a/checks/check38 b/checks/check38
index f018875132..ddc69d3689 100644
--- a/checks/check38
+++ b/checks/check38
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name S3BucketConfigChanges \
+# --filter-pattern '{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }' \
+# --metric-transformations metricName=S3BucketEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name S3BucketConfigChangesAlarm \
+# --alarm-description "Triggered by AWS S3 Bucket config changes." \
+# --metric-name S3BucketEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check38="3.8,3.08"
CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check38="LEVEL1"
CHECK_ALTERNATE_check308="check38"
check38(){
- check3x '\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication'
+ check3x '\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication'
}
diff --git a/checks/check39 b/checks/check39
index d8feb0de29..3a812a4ae5 100644
--- a/checks/check39
+++ b/checks/check39
@@ -7,6 +7,31 @@
#
# You should have received a copy of the license along with this
# work. If not, see .
+#
+# Remediation:
+#
+# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
+#
+# aws logs put-metric-filter \
+# --region us-east-1 \
+# --log-group-name CloudTrail/CloudWatchLogGroup \
+# --filter-name AWSConfigChanges \
+# --filter-pattern '{ ($.eventSource = config.amazonaws.com) && (($.eventName = StopConfigurationRecorder)||($.eventName = DeleteDeliveryChannel)||($.eventName = PutDeliveryChannel)||($.eventName = PutConfigurationRecorder)) }' \
+# --metric-transformations metricName=ConfigEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
+#
+# aws cloudwatch put-metric-alarm \
+# --region us-east-1 \
+# --alarm-name AWSConfigChangesAlarm \
+# --alarm-description "Triggered by AWS Config changes." \
+# --metric-name ConfigEventCount \
+# --namespace CloudTrailMetrics \
+# --statistic Sum \
+# --comparison-operator GreaterThanOrEqualToThreshold \
+# --evaluation-periods 1 \
+# --period 300 \
+# --threshold 1 \
+# --actions-enabled \
+# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
CHECK_ID_check39="3.9,3.09"
CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)"
@@ -15,5 +40,5 @@ CHECK_TYPE_check39="LEVEL2"
CHECK_ALTERNATE_check309="check39"
check39(){
- check3x '\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder'
+ check3x '\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder'
}
diff --git a/checks/check_extra718 b/checks/check_extra718
index e5b326907e..7331911397 100644
--- a/checks/check_extra718
+++ b/checks/check_extra718
@@ -21,11 +21,15 @@ extra718(){
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
if [[ $LIST_OF_BUCKETS ]]; then
for bucket in $LIST_OF_BUCKETS;do
- BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$")
- if [[ $BUCKET_SERVER_LOG_ENABLED ]];then
- textPass "Bucket $bucket has server access logging enabled"
- else
+ BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text 2>&1)
+ if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep AccessDenied) ]]; then
+ textFail "Access Denied Trying to Get Bucket Logging for $bucket"
+ continue
+ fi
+ if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep "^None$") ]]; then
textFail "Bucket $bucket has server access logging disabled!"
+ else
+ textPass "Bucket $bucket has server access logging enabled"
fi
done
else
diff --git a/checks/check_extra726 b/checks/check_extra726
index 6b0bd0b170..e58d888483 100644
--- a/checks/check_extra726
+++ b/checks/check_extra726
@@ -22,10 +22,14 @@ extra726(){
# forcing us-east-1 region only since support only works in that region
TA_CHECKS_ID=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query checks[*].id --output text)
for checkid in $TA_CHECKS_ID; do
- QUERY_RESULT_NO_OK=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text | grep -v "ok" )
- if [[ $QUERY_RESULT_NO_OK ]]; then
- TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text)
- textFail "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_RESULT_NO_OK"
+ TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text)
+ QUERY_TA_CHECK_RESULT=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text)
+ if [[ $(echo $QUERY_TA_CHECK_RESULT | grep ok) ]]; then
+ textPass "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT"
+ elif [[ $(echo $QUERY_TA_CHECK_RESULT | grep warning) ]]; then
+ textInfo "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT"
+ else
+ textFail "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT"
fi
done
}
diff --git a/checks/check_extra73 b/checks/check_extra73
index 3b0efc1abf..8e203b7985 100644
--- a/checks/check_extra73
+++ b/checks/check_extra73
@@ -24,7 +24,11 @@ CHECK_ALTERNATE_check703="extra73"
# extra73(){
# ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text)
# for bucket in $ALL_BUCKETS_LIST; do
-# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text)
+# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text 2>&1)
+# if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then
+# textFail "Access Denied Trying to Get Bucket Location for $bucket"
+# continue
+# fi
# if [[ "None" == $BUCKET_LOCATION ]]; then
# BUCKET_LOCATION="us-east-1"
# fi
@@ -54,7 +58,11 @@ extra73(){
S3_FINDING_POLICY="Ok"
# LOCATION
- BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text)
+ BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text 2>&1)
+ if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then
+ textFail "Access Denied Trying to Get Bucket Location for $bucket"
+ continue
+ fi
if [[ "None" == $BUCKET_LOCATION ]]; then
BUCKET_LOCATION="us-east-1"
fi
@@ -133,7 +141,11 @@ extra73(){
# }
# extra73Thread(){
# bucket=$1
-# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text)
+# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text 2>&1)
+# if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then
+# textFail "Access Denied Trying to Get Bucket Location for $bucket"
+# return
+# fi
# if [[ "None" == $BUCKET_LOCATION ]]; then
# BUCKET_LOCATION="us-east-1"
# fi
diff --git a/checks/check_extra734 b/checks/check_extra734
index 63e9aab65a..235e7423ec 100644
--- a/checks/check_extra734
+++ b/checks/check_extra734
@@ -20,31 +20,45 @@ extra734(){
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
if [[ $LIST_OF_BUCKETS ]]; then
for bucket in $LIST_OF_BUCKETS;do
+
# query to get if has encryption enabled or not
RESULT=$($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1)
- if [[ $(echo "$RESULT" | grep ServerSideEncryptionConfigurationNotFoundError) ]] ; then
- textFail "Bucket $bucket does not enforce encryption!"
- elif [[ $(echo "$RESULT" | grep AccessDenied) ]] ; then
+ if [[ $(echo "$RESULT" | grep AccessDenied) ]]; then
textFail "Access Denied Trying to Get Encryption for $bucket"
- else
- TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
- # get bucket policy
- $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null
- # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true
- CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep \"true\")
- CHECK_BUCKET_SSE_POLICY_VALUE=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep -Eo "AES256|aws:kms")
-
- echo "$RESULT" | while read RBUCKET SSEALG; do
- if [[ $SSEALG ]]; then
- textPass "Bucket $RBUCKET has default encryption enabled with algorithm $SSEALG"
- fi
- done
- if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT && $CHECK_BUCKET_SSE_POLICY_VALUE ]]; then
- textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE"
- fi
-
- rm -fr $TEMP_SSE_POLICY_FILE
+ continue
fi
+ if [[ $(echo "$RESULT" | grep ServerSideEncryptionConfigurationNotFoundError) ]]; then
+ textFail "Bucket $bucket does not enforce encryption!"
+ continue
+ fi
+
+ TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
+
+ # get bucket policy
+ $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null
+ if [[ $(grep AccessDenied $TEMP_SSE_POLICY_FILE) ]]; then
+ textFail "Access Denied Trying to Get Bucket Policy for $bucket"
+ rm -fr $TEMP_SSE_POLICY_FILE
+ continue
+ fi
+ if [[ $(grep NoSuchBucketPolicy $TEMP_SSE_POLICY_FILE) ]]; then
+ textFail "No bucket policy for $bucket"
+ rm -fr $TEMP_SSE_POLICY_FILE
+ continue
+ fi
+
+ # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true
+ CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and (.Principal|type == "object") and .Principal.AWS == "*" and .Action=="s3:PutObject" and .Resource==$arn and .Condition.StringNotEquals."s3:x-amz-server-side-encryption" != null)')
+ if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT == "" ]]; then
+ textFail "Bucket $bucket does not enforce encryption!"
+ rm -fr $TEMP_SSE_POLICY_FILE
+ continue
+ fi
+ CHECK_BUCKET_SSE_POLICY_VALUE=$(echo "$CHECK_BUCKET_SSE_POLICY_PRESENT" | jq -r '.Condition.StringNotEquals."s3:x-amz-server-side-encryption"')
+
+ textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE"
+
+ rm -fr $TEMP_SSE_POLICY_FILE
done
else
diff --git a/checks/check_extra742 b/checks/check_extra742
index c67018348f..9fff16c7b2 100644
--- a/checks/check_extra742
+++ b/checks/check_extra742
@@ -41,10 +41,11 @@ extra742(){
rm -f $CFN_OUTPUTS_FILE
else
textFail "$regx: Potential secret found in stack $stack Outputs" "$regx"
+ # delete file to not leave trace, user must look at the CFN Stack
+ rm -f $CFN_OUTPUTS_FILE
fi
else
textInfo "$regx: CloudFormation stack $stack has not Outputs" "$regx"
- rm -f $CFN_OUTPUTS_FILE
fi
done
else
diff --git a/checks/check_extra75 b/checks/check_extra75
index 3e05046220..f200762127 100644
--- a/checks/check_extra75
+++ b/checks/check_extra75
@@ -21,12 +21,25 @@ CHECK_ALTERNATE_check705="extra75"
extra75(){
# "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)"
textInfo "Looking for Security Groups in all regions... "
+
for regx in $REGIONS; do
- LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS)
+ SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --max-items $MAXITEMS | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add')
+ if [[ $SECURITYGROUPS == "null" ]];
+ then
+ continue
+ fi
+ LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUPS|jq -r 'to_entries|sort_by(.key)|.[]|.key')
for SG_ID in $LIST_OF_SECURITYGROUPS; do
SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text)
+ # Default security groups can not be deleted, so draw attention to them
if [[ $SG_NOT_USED -eq 0 ]];then
- textFail "$regx: $SG_ID is not being used!" "$regx"
+ GROUP_NAME=$(echo $SECURITYGROUPS | jq -r --arg id $SG_ID '.[$id]')
+ if [[ $GROUP_NAME != "default" ]];
+ then
+ textFail "$regx: $SG_ID is not being used!" "$regx"
+ else
+ textInfo "$regx: $SG_ID is not being used - default security group" "$regx"
+ fi
else
textPass "$regx: $SG_ID is being used" "$regx"
fi
diff --git a/checks/check_extra756 b/checks/check_extra756
index 506ebd4d3d..538fa55b08 100644
--- a/checks/check_extra756
+++ b/checks/check_extra756
@@ -18,10 +18,10 @@ CHECK_ALTERNATE_check756="extra756"
extra756(){
for regx in $REGIONS; do
- LIST_OF_RS_CLUSTERS=$($AWSCLI $PROFILE_OPT --region $regx redshift describe-clusters --query Clusters[*].ClusterIdentifier --output text)
+ LIST_OF_RS_CLUSTERS=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --query Clusters[*].ClusterIdentifier --output text)
if [[ $LIST_OF_RS_CLUSTERS ]];then
for cluster in $LIST_OF_RS_CLUSTERS; do
- IS_PUBLICLY_ACCESSIBLE=$($AWSCLI $PROFILE_OPT --region $regx redshift describe-clusters --cluster-identifier $cluster --query Clusters[*].PubliclyAccessible --output text|grep True)
+ IS_PUBLICLY_ACCESSIBLE=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --cluster-identifier $cluster --query Clusters[*].PubliclyAccessible --output text|grep True)
if [[ $IS_PUBLICLY_ACCESSIBLE ]]; then
textFail "$regx: Redshift cluster $cluster is publicly accessible" "$regx"
else
@@ -29,7 +29,7 @@ extra756(){
fi
done
else
- textInfo "$regx: Redshift clusters found" "$regx"
+ textInfo "$regx: No Redshift clusters found" "$regx"
fi
done
}
diff --git a/checks/check_extra761 b/checks/check_extra761
index a74f76de3e..542186188f 100644
--- a/checks/check_extra761
+++ b/checks/check_extra761
@@ -19,7 +19,15 @@ CHECK_ALTERNATE_check761="extra761"
extra761(){
textInfo "Looking for EBS Default Encryption activation in all regions... "
for regx in $REGIONS; do
- EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault')
+ EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault' 2>&1)
+ if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep "argument operation: Invalid choice") ]]; then
+ textFail "Newer aws cli needed for get-ebs-encryption-by-default"
+ continue
+ fi
+ if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then
+ textFail "Prowler needs ec2:GetEbsEncryptionByDefault permission for this check"
+ continue
+ fi
if [[ $EBS_DEFAULT_ENCRYPTION == "true" ]];then
textPass "$regx: EBS Default Encryption is activated" "$regx"
else
diff --git a/checks/check_extra763 b/checks/check_extra763
index 2798330424..5aa7765102 100644
--- a/checks/check_extra763
+++ b/checks/check_extra763
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
+# Prowler - the handy cloud security tool (copyright 2018) 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
@@ -11,45 +11,28 @@
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra763="7.63"
-CHECK_TITLE_extra763="[extra763] Find secrets in ECS task definitions variables (Not Scored) (Not part of CIS benchmark)"
+CHECK_TITLE_extra763="[extra763] Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)"
CHECK_SCORED_extra763="NOT_SCORED"
CHECK_TYPE_extra763="EXTRA"
CHECK_ALTERNATE_check763="extra763"
extra763(){
- SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
- if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
- # this folder is deleted once this check is finished
- mkdir $SECRETS_TEMP_FOLDER
- fi
-
- textInfo "Looking for secrets in ECS task definitions' environment variables across all regions... "
- for regx in $REGIONS; do
- LIST_OF_TASK_DEFINITIONS=$($AWSCLI ecs list-task-definitions $PROFILE_OPT --region $regx --query taskDefinitionArns[*] --output text)
- if [[ $LIST_OF_TASK_DEFINITIONS ]]; then
- for taskDefinition in $LIST_OF_TASK_DEFINITIONS;do
- IFS='/' read -r -a splitArn <<< "$taskDefinition"
- TASK_DEFINITION=${splitArn[1]}
- TASK_DEFINITION_ENV_VARIABLES_FILE="$SECRETS_TEMP_FOLDER/extra763-$TASK_DEFINITION-$regx-variables.txt"
- TASK_DEFINITION_ENV_VARIABLES=$($AWSCLI ecs $PROFILE_OPT --region $regx describe-task-definition --task-definition $taskDefinition --query 'taskDefinition.containerDefinitions[*].environment' --output text > $TASK_DEFINITION_ENV_VARIABLES_FILE)
- if [ -s $TASK_DEFINITION_ENV_VARIABLES_FILE ];then
- # Implementation using https://github.com/Yelp/detect-secrets
- FINDINGS=$(secretsDetector file $TASK_DEFINITION_ENV_VARIABLES_FILE)
- if [[ $FINDINGS -eq 0 ]]; then
- textPass "$regx: No secrets found in ECS task definition $TASK_DEFINITION variables" "$regx"
- # delete file if nothing interesting is there
- rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE
- else
- textFail "$regx: Potential secret found in ECS task definition $TASK_DEFINITION variables" "$regx"
- fi
- else
- textInfo "$regx: ECS task definition $TASK_DEFINITION has no variables" "$regx"
- rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE
- fi
- done
- else
- textInfo "$regx: No ECS task definitions found" "$regx"
- fi
- done
-# rm -rf $SECRETS_TEMP_FOLDER
+ # "Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)"
+ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
+ if [[ $LIST_OF_BUCKETS ]]; then
+ for bucket in $LIST_OF_BUCKETS;do
+ BUCKET_VERSIONING_ENABLED=$($AWSCLI s3api get-bucket-versioning --bucket $bucket $PROFILE_OPT --query Status --output text 2>&1)
+ if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep AccessDenied) ]]; then
+ textFail "Access Denied Trying to Get Bucket Versioning for $bucket"
+ continue
+ fi
+ if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then
+ textPass "Bucket $bucket has versioning enabled"
+ else
+ textFail "Bucket $bucket has versioning disabled!"
+ fi
+ done
+ else
+ textInfo "No S3 Buckets found"
+ fi
}
diff --git a/checks/check_extra764 b/checks/check_extra764
new file mode 100644
index 0000000000..fc3e70097d
--- /dev/null
+++ b/checks/check_extra764
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+# Prowler - the handy cloud security tool (copyright 2018) 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.
+CHECK_ID_extra764="7.64"
+CHECK_TITLE_extra764="[extra764] Check if S3 buckets have secure transport policy (Not Scored) (Not part of CIS benchmark)"
+CHECK_SCORED_extra764="NOT_SCORED"
+CHECK_TYPE_extra764="EXTRA"
+CHECK_ALTERNATE_check764="extra764"
+
+extra764(){
+ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
+ if [[ $LIST_OF_BUCKETS ]]; then
+ for bucket in $LIST_OF_BUCKETS;do
+ TEMP_STP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
+
+ # get bucket policy
+ $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_STP_POLICY_FILE 2>&1
+ if [[ $(grep AccessDenied $TEMP_STP_POLICY_FILE) ]]; then
+ textFail "Access Denied Trying to Get Bucket Policy for $bucket"
+ continue
+ fi
+ if [[ $(grep NoSuchBucketPolicy $TEMP_STP_POLICY_FILE) ]]; then
+ textFail "No bucket policy for $bucket"
+ continue
+ fi
+
+ # check if the S3 policy denies all actions by all principals when aws:SecureTransport:false
+ CHECK_BUCKET_STP_POLICY_PRESENT=$(cat $TEMP_STP_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and (.Principal|type == "object") and .Principal.AWS == "*" and .Action=="s3:*" and .Resource==$arn and .Condition.Bool."aws:SecureTransport" == "false")')
+ if [[ $CHECK_BUCKET_STP_POLICY_PRESENT ]]; then
+ textPass "Bucket $bucket has S3 bucket policy to deny requests over insecure transport"
+ else
+ textFail "Bucket $bucket allows requests over insecure transport"
+ fi
+
+ rm -fr $TEMP_STP_POLICY_FILE
+ done
+
+ else
+ textInfo "No S3 Buckets found"
+ fi
+}
diff --git a/checks/check_extra765 b/checks/check_extra765
new file mode 100644
index 0000000000..3792db18ac
--- /dev/null
+++ b/checks/check_extra765
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# Prowler - the handy cloud security tool (copyright 2018) 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.
+
+# Remediation:
+#
+# https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html
+#
+# aws ecr put-image-scanning-configuration \
+# --region \
+# --repository-name \
+# --image-scanning-configuration scanOnPush=true
+
+
+CHECK_ID_extra765="7.65"
+CHECK_TITLE_extra765="[extra765] Check if ECR image scan on push is enabled (Not Scored) (Not part of CIS benchmark)"
+CHECK_SCORED_extra765="NOT_SCORED"
+CHECK_TYPE_extra765="EXTRA"
+CHECK_ALTERNATE_check765="extra765"
+
+extra765(){
+ for regx in $REGIONS; do
+ LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query "repositories[*].[repositoryName]" --output text 2>&1)
+ if [[ $LIST_ECR_REPOS ]]; then
+ for repo in $LIST_ECR_REPOS; do
+ SCAN_ENABLED=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query "repositories[?repositoryName==\`$repo\`].[imageScanningConfiguration.scanOnPush]" --output text|grep True)
+ if [[ $SCAN_ENABLED ]];then
+ textPass "$regx: ECR repository $repo has scan on push enabled" "$regx"
+ else
+ textFail "$regx: ECR repository $repo has scan on push disabled!" "$regx"
+ fi
+ done
+ else
+ textInfo "$regx: No ECR repositories found" "$regx"
+ fi
+ done
+}
diff --git a/checks/check_extra767 b/checks/check_extra767
new file mode 100644
index 0000000000..1bbe4d8a7d
--- /dev/null
+++ b/checks/check_extra767
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Prowler - the handy cloud security tool (copyright 2018) 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.
+CHECK_ID_extra767="7.67"
+CHECK_TITLE_extra767="[extra767] Check if CloudFront distributions have Field Level Encryption enabled (Not Scored) (Not part of CIS benchmark)"
+CHECK_SCORED_extra767="NOT_SCORED"
+CHECK_TYPE_extra767="EXTRA"
+CHECK_ALTERNATE_check767="extra767"
+
+extra767(){
+ LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions --query 'DistributionList.Items[*].Id' $PROFILE_OPT --output text|grep -v ^None)
+ if [[ $LIST_OF_DISTRIBUTIONS ]];then
+ for dist in $LIST_OF_DISTRIBUTIONS; do
+ CHECK_FLE=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.DefaultCacheBehavior.FieldLevelEncryptionId $PROFILE_OPT --output text)
+ if [[ $CHECK_FLE ]]; then
+ textPass "CloudFront distribution $dist has Field Level Encryption enabled" "$regx"
+ else
+ textFail "CloudFront distribution $dist has Field Level Encryption disabled!" "$regx"
+ fi
+ done
+ else
+ textInfo "No CloudFront distributions found" "$regx"
+ fi
+}
diff --git a/groups/group7_extras b/groups/group7_extras
index b186e032b1..c3d80d3487 100644
--- a/groups/group7_extras
+++ b/groups/group7_extras
@@ -15,7 +15,7 @@ GROUP_ID[7]='extras'
GROUP_NUMBER[7]='7.0'
GROUP_TITLE[7]='Extras - [extras] **********************************************'
GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called
-GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762'
+GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767'
# Extras 759 and 760 (lambda variables and code secrets finder are not included)
# to run detect-secrets use `./prowler -g secrets`
diff --git a/iam/prowler-policy-additions.json b/iam/prowler-policy-additions.json
index 7b2f2f7999..49c7287ce1 100644
--- a/iam/prowler-policy-additions.json
+++ b/iam/prowler-policy-additions.json
@@ -5,18 +5,19 @@
"Action": [
"acm:describecertificate",
"acm:listcertificates",
+ "apigateway:GET",
+ "cloudtrail:GetEventSelectors",
+ "ec2:GetEbsEncryptionByDefault",
"es:describeelasticsearchdomainconfig",
+ "guardduty:GetDetector",
+ "guardduty:ListDetectors",
"logs:DescribeLogGroups",
"logs:DescribeMetricFilters",
+ "s3:GetEncryptionConfiguration",
"ses:getidentityverificationattributes",
"sns:listsubscriptionsbytopic",
- "guardduty:ListDetectors",
- "guardduty:GetDetector",
- "S3:GetEncryptionConfiguration",
- "trustedadvisor:Describe*",
- "cloudtrail:GetEventSelectors",
- "apigateway:GET",
- "support:*"
+ "support:*",
+ "trustedadvisor:Describe*"
],
"Effect": "Allow",
"Resource": "*"
diff --git a/util/multi-account/Audit_Exec_Role.yaml b/util/multi-account/Audit_Exec_Role.yaml
index 673defaa2e..a89950a34c 100644
--- a/util/multi-account/Audit_Exec_Role.yaml
+++ b/util/multi-account/Audit_Exec_Role.yaml
@@ -50,18 +50,20 @@ Resources:
Action:
- "acm:describecertificate"
- "acm:listcertificates"
+ - "apigateway:GET"
+ - "cloudtrail:GetEventSelectors"
+ - "ec2:GetEbsEncryptionByDefault"
- "es:describeelasticsearchdomainconfig"
- - "logs:DescribeLogGroups"
- - "logs:DescribeMetricFilters"
- - "ses:getidentityverificationattributes"
- - "sns:listsubscriptionsbytopic"
- "guardduty:ListDetectors"
- "guardduty:GetDetector"
- - "S3:GetEncryptionConfiguration"
- - "trustedadvisor:Describe*"
- - "cloudtrail:GetEventSelectors"
- - "apigateway:GET"
+ - "logs:DescribeLogGroups"
+ - "logs:DescribeMetricFilters"
+ - "s3:GetEncryptionConfiguration"
+ - "ses:getidentityverificationattributes"
+ - "sns:listsubscriptionsbytopic"
- "support:*"
+ - "trustedadvisor:Describe*"
+
Metadata:
cfn_nag:
rules_to_suppress:
diff --git a/util/multi-account/Audit_Pipeline.yaml b/util/multi-account/Audit_Pipeline.yaml
index acd0c21652..92b74a6aab 100644
--- a/util/multi-account/Audit_Pipeline.yaml
+++ b/util/multi-account/Audit_Pipeline.yaml
@@ -301,9 +301,6 @@ Resources:
discard-paths: no
base-directory: out
-
-
-
ProwlerAuditTriggerRole:
Type: AWS::IAM::Role
Properties: