feat(EC2): add EC2 tests and checks (#1482)

Co-authored-by: sergargar <sergio@verica.io>
This commit is contained in:
Sergio Garcia
2022-11-17 21:01:47 +01:00
committed by GitHub
parent 6ff9f30473
commit 967990b76d
135 changed files with 5719 additions and 1306 deletions

View File

@@ -1,62 +0,0 @@
#!/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_extra7102="7.102"
CHECK_TITLE_extra7102="[extra7102] Check if any of the Elastic or Public IP are in Shodan (requires Shodan API KEY)"
CHECK_SCORED_extra7102="NOT_SCORED"
CHECK_CIS_LEVEL_extra7102="EXTRA"
CHECK_SEVERITY_extra7102="High"
CHECK_ASFF_RESOURCE_TYPE_extra7102="AwsEc2Eip"
CHECK_ALTERNATE_check7102="extra7102"
CHECK_SERVICENAME_extra7102="ec2"
CHECK_RISK_extra7102='Sites like Shodan index exposed systems and further expose them to wider audiences as a quick way to find exploitable systems.'
CHECK_REMEDIATION_extra7102='Check Identified IPs; consider changing them to private ones and delete them from Shodan.'
CHECK_DOC_extra7102='https://www.shodan.io/'
CHECK_CAF_EPIC_extra7102='Infrastructure Security'
# Watch out, always use Shodan API key, if you use `curl https://www.shodan.io/host/{ip}` massively
# your IP will be banned by Shodan
# This is the right way to do so
# curl -ks https://api.shodan.io/shodan/host/{ip}?key={YOUR_API_KEY}
# Each finding will be saved in prowler/output folder for further review.
extra7102(){
if [[ ! $SHODAN_API_KEY ]]; then
textInfo "[extra7102] Requires a Shodan API key to work. Use -N <shodan_api_key>"
else
for regx in $REGIONS; do
LIST_OF_EIP=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Association.PublicIp' --output text 2>&1)
if [[ $(echo "$LIST_OF_EIP" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe network interfaces" "$regx"
continue
fi
if [[ $LIST_OF_EIP ]]; then
for ip in $LIST_OF_EIP;do
SHODAN_QUERY=$(curl -ks https://api.shodan.io/shodan/host/$ip?key=$SHODAN_API_KEY)
# Shodan has a request rate limit of 1 request/second.
sleep 1
if [[ $SHODAN_QUERY == *"No information available for that IP"* ]]; then
textPass "$regx: IP $ip is not listed in Shodan" "$regx"
else
echo $SHODAN_QUERY > $OUTPUT_DIR/shodan-output-$ip.json
IP_SHODAN_INFO=$(cat $OUTPUT_DIR/shodan-output-$ip.json | jq -r '. | { ports: .ports, org: .org, country: .country_name }| @text' | tr -d \"\{\}\}\]\[ | tr , '\ ' )
textFail "$regx: IP $ip is listed in Shodan with data $IP_SHODAN_INFO. More info https://www.shodan.io/host/$ip and $OUTPUT_DIR/shodan-output-$ip.json" "$regx" "$ip"
fi
done
else
textInfo "$regx: No Public or Elastic IPs found" "$regx"
fi
done
fi
}

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra7135="7.135"
CHECK_TITLE_extra7135="[extra7135] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Kafka port 9092 "
CHECK_SCORED_extra7135="NOT_SCORED"
CHECK_CIS_LEVEL_extra7135="EXTRA"
CHECK_SEVERITY_extra7135="High"
CHECK_ASFF_RESOURCE_TYPE_extra7135="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check7135="extra7135"
CHECK_SERVICENAME_extra7135="ec2"
CHECK_RISK_extra7135='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra7135='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra7135='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra7135='Infrastructure Security'
extra7135(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`9092` && ToPort==`9092`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Kafka ports" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Kafka ports" "$regx"
fi
done
}

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra7136="7.136"
CHECK_TITLE_extra7136="[extra7136] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Telnet port 23 "
CHECK_SCORED_extra7136="NOT_SCORED"
CHECK_CIS_LEVEL_extra7136="EXTRA"
CHECK_SEVERITY_extra7136="High"
CHECK_ASFF_RESOURCE_TYPE_extra7136="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check7136="extra7136"
CHECK_SERVICENAME_extra7136="ec2"
CHECK_RISK_extra7136='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra7136='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra7136='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra7136='Infrastructure Security'
extra7136(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`23` && ToPort==`23`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Telnet ports" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Telnet ports" "$regx" "$SG"
fi
done
}

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra7137="7.137"
CHECK_TITLE_extra7137="[extra7137] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Windows SQL Server ports 1433 or 1434 "
CHECK_SCORED_extra7137="NOT_SCORED"
CHECK_CIS_LEVEL_extra7137="EXTRA"
CHECK_SEVERITY_extra7137="High"
CHECK_ASFF_RESOURCE_TYPE_extra7137="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check7137="extra7137"
CHECK_SERVICENAME_extra7137="ec2"
CHECK_RISK_extra7137='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra7137='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra7137='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra7137='Infrastructure Security'
extra7137(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`1433` && ToPort==`1434`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Microsoft SQL Server ports" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Microsoft SQL Server ports" "$regx"
fi
done
}

View File

@@ -1,47 +0,0 @@
#!/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_extra7146="7.146"
CHECK_TITLE_extra7146="[extra7146] Check if there is any unassigned Elastic IP"
CHECK_SCORED_extra7146="NOT_SCORED"
CHECK_CIS_LEVEL_extra7146="EXTRA"
CHECK_SEVERITY_extra7146="Low"
CHECK_ASFF_RESOURCE_TYPE_extra7146="AwsElasticIPs"
CHECK_ALTERNATE_check7146="extra7146"
CHECK_SERVICENAME_extra7146="ec2"
CHECK_RISK_extra7146='Unassigned Elastic IPs may result in extra cost'
CHECK_REMEDIATION_extra7146='Ensure Elastic IPs are not unassigned'
CHECK_DOC_extra7146='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html'
CHECK_CAF_EPIC_extra7146='Infrastructure Security'
extra7146(){
# "Check if there is any unassigned elastic ip (Not Scored) (Not part of CIS benchmark)"
for regx in $REGIONS; do
ELASTIC_IP_ADDRESSES=$($AWSCLI ec2 describe-addresses $PROFILE_OPT --region $regx --query Addresses --output json 2>&1)
if [[ $(echo "$ELASTIC_IP_ADDRESSES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe addresses" "$regx"
continue
fi
if [[ $ELASTIC_IP_ADDRESSES != [] ]]; then
LIST_OF_ASSOCIATED_IPS=$(echo $ELASTIC_IP_ADDRESSES | jq -r '.[] | select(.AssociationId!=null) | .PublicIp')
LIST_OF_UNASSOCIATED_IPS=$(echo $ELASTIC_IP_ADDRESSES | jq -r '.[] | select(.AssociationId==null) | .PublicIp')
for ass_ip in $LIST_OF_ASSOCIATED_IPS; do
textPass "$regx: Elastic IP $ass_ip is associated with an instance or network interface" "$regx" "$ass_ip"
done
for unass_ip in $LIST_OF_UNASSOCIATED_IPS; do
textInfo "$regx: Elastic IP $unass_ip is not associated with any instance or network interface and it may incurr extra cost" "$regx" "$unass_ip"
done
else
textInfo "$regx: No Elastic IPs found" "$regx"
fi
done
}

View File

@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra7173="7.173"
CHECK_TITLE_extra7173="[check7173] Security Groups created by EC2 Launch Wizard"
CHECK_SCORED_extra7173="NOT_SCORED"
CHECK_CIS_LEVEL_extra7173="EXTRA"
CHECK_SEVERITY_extra7173="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7173="AwsEc2SecurityGroup"
CHECK_ALTERNATE_extra7173="extra7173"
CHECK_SERVICENAME_extra7173="ec2"
CHECK_RISK_cextra7173="Security Groups Created on the AWS Console using the EC2 wizard may allow port 22 from 0.0.0.0/0"
CHECK_REMEDIATION_extra7173="Apply Zero Trust approach. Implement a process to scan and remediate security groups created by the EC2 Wizard. Recommended best practices is to use an authorized security group."
CHECK_DOC_extra7173="CHECK_DOC_extra7173='https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html'"
CHECK_CAF_EPIC_extra7173="Infrastructure Security"
extra7173(){
# Ensure no security groups are created using Console EC2 Wizard
for regx in $REGIONS; do
CHECK_SGDEFAULT_IDS=$("${AWSCLI}" ec2 describe-security-groups ${PROFILE_OPT} --region "${regx}" --filters Name=group-name,Values='launch-wizard-*' --query 'SecurityGroups[*].GroupId[]' --output text 2>&1)
if grep -q -E 'AccessDenied|UnauthorizedOperation' <<< "${CHECK_SGDEFAULT_IDS}"; then
textInfo "${regx}: Access Denied trying to describe security groups" "${regx}"
continue
fi
if [[ ${CHECK_SGDEFAULT_IDS} ]]; then
for CHECK_SGDEFAULT_ID in ${CHECK_SGDEFAULT_IDS}; do
SECURITY_GROUP_NAME=$(${AWSCLI} ec2 describe-security-groups ${PROFILE_OPT} --region "${regx}" --group-ids "${CHECK_SGDEFAULT_ID}" --query 'SecurityGroups[*].GroupName[]' --output text 2>&1)
textFail "${regx}: Security Group ${SECURITY_GROUP_NAME} (ID: ${CHECK_SGDEFAULT_ID}) was created using the EC2 Launch Wizard" "${regx}" "${CHECK_SGDEFAULT_ID}"
done
else
textPass "${regx}: No Security Groups found that were created using the Wizard" "${regx}" "${CHECK_SGDEFAULT_ID}"
fi
done
}

View File

@@ -1,46 +0,0 @@
#!/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_extra74="7.4"
CHECK_TITLE_extra74="[extra74] Ensure there are no Security Groups without ingress filtering being used"
CHECK_SCORED_extra74="NOT_SCORED"
CHECK_CIS_LEVEL_extra74="EXTRA"
CHECK_SEVERITY_extra74="High"
CHECK_ASFF_RESOURCE_TYPE_extra74="AwsEc2SecurityGroup"
CHECK_ALTERNATE_extra704="extra74"
CHECK_ALTERNATE_check74="extra74"
CHECK_ALTERNATE_check704="extra74"
CHECK_ASFF_COMPLIANCE_TYPE_extra74="ens-mp.com.4.aws.sg.2"
CHECK_SERVICENAME_extra74="ec2"
CHECK_RISK_extra74='If Security groups are not filtering traffic appropriately the attack surface is increased.'
CHECK_REMEDIATION_extra74=' You can grant access to a specific CIDR range; or to another security group in your VPC or in a peer VPC.'
CHECK_DOC_extra74='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra74='Infrastructure Security'
extra74(){
# "Ensure there are no Security Groups without ingress filtering being used "
for regx in $REGIONS; do
LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS 2>&1)
if [[ $(echo "$LIST_OF_SECURITYGROUPS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
for SG_ID in $LIST_OF_SECURITYGROUPS; do
SG_NO_INGRESS_FILTER=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text)
if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then
textFail "$regx: $SG_ID has no ingress filtering and it is being used!" "$regx" "$SG_ID"
else
textInfo "$regx: $SG_ID has no ingress filtering but it is not being used" "$regx" "$SG_ID"
fi
done
done
}

View File

@@ -1,75 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra741="7.41"
CHECK_TITLE_extra741="[extra741] Find secrets in EC2 User Data"
CHECK_SCORED_extra741="NOT_SCORED"
CHECK_CIS_LEVEL_extra741="EXTRA"
CHECK_SEVERITY_extra741="Critical"
CHECK_ASFF_RESOURCE_TYPE_extra741="AwsEc2Instance"
CHECK_ALTERNATE_check741="extra741"
CHECK_SERVICENAME_extra741="ec2"
CHECK_RISK_extra741='Secrets hardcoded into instance user data can be used by malware and bad actors to gain lateral access to other services.'
CHECK_REMEDIATION_extra741='Implement automated detective control (e.g. using tools like Prowler ) to scan accounts for passwords and secrets. Use secrets manager service to store and retrieve passwords and secrets. '
CHECK_DOC_extra741='https://docs.aws.amazon.com/secretsmanager/latest/userguide/tutorials_basic.html'
CHECK_CAF_EPIC_extra741='IAM'
extra741(){
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
for regx in $REGIONS; do
CHECK_DETECT_SECRETS_INSTALLATION=$(secretsDetector)
if [[ $? -eq 241 ]]; then
textInfo "$regx: python library detect-secrets not found. Make sure it is installed correctly." "$regx"
else
LIST_OF_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query Reservations[*].Instances[*].InstanceId --output text --max-items $MAXITEMS 2>&1| grep -v None)
if [[ $(echo "$LIST_OF_EC2_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe instances" "$regx"
continue
fi
if [[ $LIST_OF_EC2_INSTANCES ]];then
for instance in $LIST_OF_EC2_INSTANCES; do
EC2_USERDATA_FILE="$SECRETS_TEMP_FOLDER/extra741-$instance-userData.decoded"
EC2_USERDATA=$($AWSCLI ec2 describe-instance-attribute --attribute userData $PROFILE_OPT --region $regx --instance-id $instance --query UserData.Value --output text| grep -v ^None | decode_report > $EC2_USERDATA_FILE)
if [ -s "$EC2_USERDATA_FILE" ];then
# This finds ftp or http URLs with credentials and common keywords
# FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $EC2_USERDATA_FILE |wc -l|tr -d '\ ')
# New implementation using https://github.com/Yelp/detect-secrets
# Test if user data is a valid GZIP file, if so gunzip first
if gunzip -t "$EC2_USERDATA_FILE" > /dev/null 2>&1; then
mv "$EC2_USERDATA_FILE" "$EC2_USERDATA_FILE.gz" ; gunzip "$EC2_USERDATA_FILE.gz"
fi
FINDINGS=$(secretsDetector file "$EC2_USERDATA_FILE")
if [[ $FINDINGS -eq 0 ]]; then
textPass "$regx: No secrets found in $instance User Data" "$regx" "$instance"
# delete file if nothing interesting is there
rm -f "$EC2_USERDATA_FILE"
else
textFail "$regx: Potential secret found in $instance User Data" "$regx" "$instance"
# delete file to not leave trace, user must look at the instance User Data
rm -f "$EC2_USERDATA_FILE"
fi
else
textPass "$regx: No secrets found in $instance User Data or it is empty" "$regx" "$instance"
fi
done
else
textInfo "$regx: No EC2 instances found" "$regx"
fi
fi
done
rm -rf $SECRETS_TEMP_FOLDER
}

View File

@@ -1,59 +0,0 @@
#!/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_extra75="7.5"
CHECK_TITLE_extra75="[extra75] Ensure there are no Security Groups not being used"
CHECK_SCORED_extra75="NOT_SCORED"
CHECK_CIS_LEVEL_extra75="EXTRA"
CHECK_SEVERITY_extra75="Informational"
CHECK_ASFF_RESOURCE_TYPE_extra75="AwsEc2SecurityGroup"
CHECK_ALTERNATE_extra705="extra75"
CHECK_ALTERNATE_check75="extra75"
CHECK_ALTERNATE_check705="extra75"
CHECK_ASFF_COMPLIANCE_TYPE_extra75="ens-mp.com.4.aws.sg.3"
CHECK_SERVICENAME_extra75="ec2"
CHECK_RISK_extra75='Having clear definition and scope for Security Groups creates a better administration environment.'
CHECK_REMEDIATION_extra75='List all the security groups and then use the cli to check if they are attached to an instance.'
CHECK_DOC_extra75='https://aws.amazon.com/premiumsupport/knowledge-center/ec2-find-security-group-resources/'
CHECK_CAF_EPIC_extra75='Infrastructure Security'
extra75(){
# "Ensure there are no Security Groups not being used "
for regx in $REGIONS; do
SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --max-items $MAXITEMS --output json 2>&1 )
if [[ $(echo "$SECURITYGROUPS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $(echo "$SECURITYGROUPS" | jq '."SecurityGroups" | length') -eq 0 ]]; then
textInfo "$regx: No Security Groups found in $regx" "$regx"
continue
fi
SECURITYGROUP_NAMES=$(echo $SECURITYGROUPS | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add')
LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUP_NAMES | 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
GROUP_NAME=$(echo $SECURITYGROUP_NAMES | jq -r --arg id $SG_ID '.[$id]')
if [[ $GROUP_NAME != "default" ]];
then
textFail "$regx: $SG_ID is not being used!" "$regx" "$SG_ID"
else
textInfo "$regx: $SG_ID is not being used - default security group" "$regx" "$SG_ID"
fi
else
textPass "$regx: $SG_ID is being used" "$regx" "$SG_ID"
fi
done
done
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra751="7.51"
CHECK_TITLE_extra751="[extra751] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432"
CHECK_SCORED_extra751="NOT_SCORED"
CHECK_CIS_LEVEL_extra751="EXTRA"
CHECK_SEVERITY_extra751="High"
CHECK_ASFF_RESOURCE_TYPE_extra751="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check751="extra751"
CHECK_ASFF_COMPLIANCE_TYPE_extra751="ens-mp.com.4.aws.sg.8"
CHECK_SERVICENAME_extra751="ec2"
CHECK_RISK_extra751='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra751='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra751='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra751='Infrastructure Security'
extra751(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`5432` && ToPort>=`5432`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Postgres port" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Postgres port" "$regx"
fi
done
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra752="7.52"
CHECK_TITLE_extra752="[extra752] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Redis port 6379"
CHECK_SCORED_extra752="NOT_SCORED"
CHECK_CIS_LEVEL_extra752="EXTRA"
CHECK_SEVERITY_extra752="High"
CHECK_ASFF_RESOURCE_TYPE_extra752="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check752="extra752"
CHECK_ASFF_COMPLIANCE_TYPE_extra752="ens-mp.com.4.aws.sg.9"
CHECK_SERVICENAME_extra752="ec2"
CHECK_RISK_extra752='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra752='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra752='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra752='Infrastructure Security'
extra752(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`6379` && ToPort>=`6379`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Redis port" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Redis port" "$regx"
fi
done
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra753="7.53"
CHECK_TITLE_extra753="[extra753] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018"
CHECK_SCORED_extra753="NOT_SCORED"
CHECK_CIS_LEVEL_extra753="EXTRA"
CHECK_SEVERITY_extra753="High"
CHECK_ASFF_RESOURCE_TYPE_extra753="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check753="extra753"
CHECK_ASFF_COMPLIANCE_TYPE_extra753="ens-mp.com.4.aws.sg.10"
CHECK_SERVICENAME_extra753="ec2"
CHECK_RISK_extra753='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra753='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra753='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra753='Infrastructure Security'
extra753(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`27017` && ToPort>=`27017`) || (FromPort<=`27018` && ToPort>=`27018`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for MongoDB ports" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for MongoDB ports" "$regx"
fi
done
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra754="7.54"
CHECK_TITLE_extra754="[extra754] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888"
CHECK_SCORED_extra754="NOT_SCORED"
CHECK_CIS_LEVEL_extra754="EXTRA"
CHECK_SEVERITY_extra754="High"
CHECK_ASFF_RESOURCE_TYPE_extra754="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check754="extra754"
CHECK_ASFF_COMPLIANCE_TYPE_extra754="ens-mp.com.4.aws.sg.11"
CHECK_SERVICENAME_extra754="ec2"
CHECK_RISK_extra754='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra754='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra754='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra754='Infrastructure Security'
extra754(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`7199` && ToPort>=`7199`) || (FromPort<=`9160` && ToPort>=`9160`)|| (FromPort<=`8888` && ToPort>=`8888`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Cassandra ports" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Cassandra ports" "$regx"
fi
done
}

View File

@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra755="7.55"
CHECK_TITLE_extra755="[extra755] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211"
CHECK_SCORED_extra755="NOT_SCORED"
CHECK_CIS_LEVEL_extra755="EXTRA"
CHECK_SEVERITY_extra755="High"
CHECK_ASFF_RESOURCE_TYPE_extra755="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check755="extra755"
CHECK_ASFF_COMPLIANCE_TYPE_extra755="ens-mp.com.4.aws.sg.12"
CHECK_SERVICENAME_extra755="ec2"
CHECK_RISK_extra755='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra755='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra755='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra755='Infrastructure Security'
extra755(){
for regx in $REGIONS; do
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`11211` && ToPort>=`11211`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
if [[ $SG_LIST ]];then
for SG in $SG_LIST;do
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Memcached port" "$regx" "$SG"
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Memcached port" "$regx"
fi
done
}

View File

@@ -1,50 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra757="7.57"
CHECK_TITLE_extra757="[extra757] Check EC2 Instances older than 6 months"
CHECK_SCORED_extra757="NOT_SCORED"
CHECK_CIS_LEVEL_extra757="EXTRA"
CHECK_SEVERITY_extra757="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra757="AwsEc2Instance"
CHECK_ALTERNATE_check757="extra757"
CHECK_SERVICENAME_extra757="ec2"
CHECK_RISK_extra757='Having old instances within your AWS account could increase the risk of having vulnerable software.'
CHECK_REMEDIATION_extra757='Check if software running in the instance is up to date and patched accordingly. Use AWS Systems Manager to patch instances and view patching compliance information.'
CHECK_DOC_extra757='https://docs.aws.amazon.com/systems-manager/latest/userguide/viewing-patch-compliance-results.html'
CHECK_CAF_EPIC_extra757='Infrastructure Security'
extra757(){
OLDAGE="$(get_date_previous_than_months 6)"
for regx in $REGIONS; do
EC2_RUNNING=$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$EC2_RUNNING" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe instances" "$regx"
continue
fi
if [[ $EC2_RUNNING ]]; then
INSTACES_OLD_THAN_AGE=$($AWSCLI ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" $PROFILE_OPT --region $regx --output text)
if [[ $INSTACES_OLD_THAN_AGE ]]; then
while IFS= read -r ec2_instace
do
EC2_ID=$(echo "$ec2_instace" | awk '{print $1}')
LAUNCH_DATE=$(echo "$ec2_instace" | awk '{print $2}')
textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx" "$EC2_ID"
done <<< "$INSTACES_OLD_THAN_AGE"
else
textPass "$regx: All Instances newer than 6 months" "$regx"
fi
else
textInfo "$regx: No EC2 Instances Found" "$regx"
fi
done
}

View File

@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra758="7.58"
CHECK_TITLE_extra758="[extra758] Check EC2 Instances older than 12 months "
CHECK_SCORED_extra758="NOT_SCORED"
CHECK_CIS_LEVEL_extra758="EXTRA"
CHECK_SEVERITY_extra758="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra758="AwsEc2Instance"
CHECK_ALTERNATE_check758="extra758"
CHECK_SERVICENAME_extra758="ec2"
CHECK_RISK_extra758='Having old instances within your AWS account could increase the risk of having vulnerable software.'
CHECK_REMEDIATION_extra758='Check if software running in the instance is up to date and patched accordingly. Use AWS Systems Manager to patch instances and view patching compliance information.'
CHECK_DOC_extra758='https://docs.aws.amazon.com/systems-manager/latest/userguide/viewing-patch-compliance-results.html'
CHECK_CAF_EPIC_extra758='Infrastructure Security'
extra758(){
# OLDAGE has the following format: YYYY-MM-DD
OLDAGE="$(get_date_previous_than_months 12)"
for regx in ${REGIONS}; do
INSTACES_OLD_THAN_AGE=$("${AWSCLI}" ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='${OLDAGE}'][].[InstanceId, LaunchTime, State.Name]" ${PROFILE_OPT} --region "${regx}" --output text 2>&1)
if [[ $(echo "${INSTACES_OLD_THAN_AGE}" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "${regx}: Access Denied trying to describe instances" "${regx}"
continue
fi
if [[ "${INSTACES_OLD_THAN_AGE}" ]]; then
while read -r EC2_ID LAUNCH_DATE STATE
do
textFail "${regx}: EC2 Instance ${EC2_ID} launched before than ${OLDAGE}. Launch date: ${LAUNCH_DATE} - State: ${STATE}" "${regx}" "${EC2_ID}"
done <<< "${INSTACES_OLD_THAN_AGE}"
else
textPass "${regx}: No EC2 Instances found older than 12 months" "${regx}"
fi
done
}

View File

@@ -1,43 +0,0 @@
#!/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_extra76="7.6"
CHECK_TITLE_extra76="[extra76] Ensure there are no EC2 AMIs set as Public"
CHECK_SCORED_extra76="NOT_SCORED"
CHECK_CIS_LEVEL_extra76="EXTRA"
CHECK_SEVERITY_extra76="Critical"
CHECK_ALTERNATE_extra706="extra76"
CHECK_ALTERNATE_check76="extra76"
CHECK_ALTERNATE_check706="extra76"
CHECK_SERVICENAME_extra76="ec2"
CHECK_RISK_extra76='A shared AMI is an AMI that a developer created and made available for other developers to use. If AMIs have embebed information about the environment could pose a security risk. You use a shared AMI at your own risk. Amazon can not vouch for the integrity or security of AMIs shared by Amazon EC2 users. '
CHECK_REMEDIATION_extra76='List all shared AMIs and make sure there is a business reason for them.'
CHECK_DOC_extra76='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingsharedamis-finding.html'
CHECK_CAF_EPIC_extra76='Infrastructure Security'
extra76(){
# "Ensure there are no EC2 AMIs set as Public "
for regx in $REGIONS; do
LIST_OF_PUBLIC_AMIS=$($AWSCLI ec2 describe-images --owners self $PROFILE_OPT --region $regx --filters "Name=is-public,Values=true" --query 'Images[*].{ID:ImageId}' --output text 2>&1)
if [[ $(echo "$LIST_OF_PUBLIC_AMIS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
textInfo "$regx: Access Denied trying to describe images" "$regx"
continue
fi
if [[ $LIST_OF_PUBLIC_AMIS ]];then
for ami in $LIST_OF_PUBLIC_AMIS; do
textFail "$regx: $ami is currently Public!" "$regx" "$ami"
done
else
textPass "$regx: No Public AMIs found" "$regx" "$ami"
fi
done
}

View File

@@ -1,43 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra761="7.61"
CHECK_TITLE_extra761="[extra761] Check if EBS Default Encryption is activated "
CHECK_SCORED_extra761="NOT_SCORED"
CHECK_CIS_LEVEL_extra761="EXTRA"
CHECK_SEVERITY_extra761="Medium"
CHECK_ALTERNATE_check761="extra761"
CHECK_ASFF_COMPLIANCE_TYPE_extra761="ens-mp.info.3.aws.ebs.2"
CHECK_SERVICENAME_extra761="ec2"
CHECK_RISK_extra761='If not enabled sensitive information at rest is not protected.'
CHECK_REMEDIATION_extra761='Enable Encryption. Use a CMK where possible. It will provide additional management and privacy benefits.'
CHECK_DOC_extra761='https://aws.amazon.com/premiumsupport/knowledge-center/ebs-automatic-encryption/'
CHECK_CAF_EPIC_extra761='Data Protection'
extra761(){
for regx in $REGIONS; do
EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault' --output text 2>&1)
if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep "argument operation: Invalid choice") ]]; then
textInfo "$regx: Newer aws cli needed for get-ebs-encryption-by-default" "$regx"
continue
fi
if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then
textInfo "$regx: Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" "$regx"
continue
fi
if [[ $EBS_DEFAULT_ENCRYPTION == "True" ]];then
textPass "$regx: EBS Default Encryption is activated" "$regx"
else
textFail "$regx: EBS Default Encryption is not activated" "$regx"
fi
done
}

View File

@@ -1,45 +0,0 @@
#!/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_extra770="7.70"
CHECK_TITLE_extra770="[extra770] Check for internet facing EC2 instances with Instance Profiles attached "
CHECK_SCORED_extra770="NOT_SCORED"
CHECK_CIS_LEVEL_extra770="EXTRA"
CHECK_SEVERITY_extra770="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra770="AwsEc2Instance"
CHECK_ALTERNATE_check770="extra770"
CHECK_SERVICENAME_extra770="ec2"
CHECK_RISK_extra770='Exposing an EC2 directly to internet increases the attack surface and therefore the risk of compromise.'
CHECK_REMEDIATION_extra770='Use an ALB and apply WAF ACL.'
CHECK_DOC_extra770='https://aws.amazon.com/blogs/aws/aws-web-application-firewall-waf-for-application-load-balancers/'
CHECK_CAF_EPIC_extra770='Infrastructure Security'
extra770(){
# "Check for internet facing EC2 Instances "
for regx in $REGIONS; do
LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?((IamInstanceProfile!=`null` && PublicIpAddress!=`null`))].[InstanceId,PublicIpAddress,IamInstanceProfile.Arn]' --output text 2>&1)
if [[ $(echo "$LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe instances" "$regx"
continue
fi
if [[ $LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES ]];then
while read -r instance;do
INSTANCE_ID=$(echo $instance | awk '{ print $1; }')
PUBLIC_IP=$(echo $instance | awk '{ print $2; }')
INSTANCE_PROFILE=$(echo $instance | awk '{ print $3; }')
textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing with Instance Profile $INSTANCE_PROFILE" "$regx" "$INSTANCE_ID"
done <<< "$LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES"
else
textPass "$regx: no Internet Facing EC2 Instances with Instance Profiles found" "$regx"
fi
done
}

View File

@@ -1,47 +0,0 @@
#!/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_extra772="7.72"
CHECK_TITLE_extra772="[extra772] Check if elastic IPs are unused "
CHECK_SCORED_extra772="NOT_SCORED"
CHECK_CIS_LEVEL_extra772="EXTRA"
CHECK_SEVERITY_extra772="Low"
CHECK_ASFF_RESOURCE_TYPE_extra772="AwsEc2Eip"
CHECK_ALTERNATE_check772="extra772"
CHECK_SERVICENAME_extra772="ec2"
CHECK_RISK_extra772='You are charged by the hour for each Elastic IP address that are not attached to an EC2 instance .'
CHECK_REMEDIATION_extra772='If you dont need an Elastic IP address; you can stop the charges by releasing the IP address.'
CHECK_DOC_extra772='https://aws.amazon.com/premiumsupport/knowledge-center/elastic-ip-charges/'
CHECK_CAF_EPIC_extra772='Infrastructure Security'
extra772(){
for region in $REGIONS; do
EIP_DUMP=$($AWSCLI ec2 describe-addresses ${PROFILE_OPT} --region $region --output json 2>&1)
if [[ $(echo "$EIP_DUMP" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe addresses" "$regx"
continue
fi
EIP_LIST=$(echo $EIP_DUMP | jq -r '.Addresses[].AllocationId')
if [[ $EIP_LIST ]]; then
for eip in $EIP_LIST; do
ASSOCIATION_ID=$(echo $EIP_DUMP | jq -r --arg i "$eip" '.Addresses[]|select(.AllocationId==$i)|.AssociationId')
if [[ "$ASSOCIATION_ID" == "null" ]]; then
textFail "$region: EIP $eip is unused" "$region" "$eip"
else
textPass "$region: EIP $eip is used" "$region" "$eip"
fi
done
else
textInfo "$region: No Elastic IPs found" $region
fi
done
}

View File

@@ -1,69 +0,0 @@
#!/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.
# Current VPC Limit is 120 rules (60 inbound and 60 outbound)
# Reference: https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html
CHECK_ID_extra777="7.77"
CHECK_TITLE_extra777="[extra777] Find VPC security groups with more than 50 ingress or egress rules "
CHECK_SCORED_extra777="NOT_SCORED"
CHECK_CIS_LEVEL_extra777="EXTRA"
CHECK_SEVERITY_extra777="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra777="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check777="extra777"
CHECK_SERVICENAME_extra777="ec2"
CHECK_RISK_extra777='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra777='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra777='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra777='Infrastructure Security'
extra777(){
THRESHOLD=50
for regx in ${REGIONS}; do
SECURITY_GROUP_IDS=$(${AWSCLI} ec2 describe-security-groups \
${PROFILE_OPT} \
--region ${regx} \
--query 'SecurityGroups[*].GroupId' \
--output text 2>&1| xargs )
if [[ $(echo "$SECURITY_GROUP_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
for SECURITY_GROUP in ${SECURITY_GROUP_IDS}; do
INGRESS_TOTAL=$(${AWSCLI} ec2 describe-security-groups \
${PROFILE_OPT} \
--filter "Name=group-id,Values=${SECURITY_GROUP}" \
--query "SecurityGroups[*].IpPermissions[*].IpRanges" \
--region ${regx} \
--output text | wc -l | xargs
)
EGRESS_TOTAL=$(${AWSCLI} ec2 describe-security-groups \
${PROFILE_OPT} \
--filter "Name=group-id,Values=${SECURITY_GROUP}" \
--query "SecurityGroups[*].IpPermissionsEgress[*].IpRanges" \
--region ${regx} \
--output text | wc -l | xargs
)
if [[ (${INGRESS_TOTAL} -ge ${THRESHOLD}) || (${EGRESS_TOTAL} -ge ${THRESHOLD}) ]]; then
textFail "${regx}: ${SECURITY_GROUP} has ${INGRESS_TOTAL} inbound rules and ${EGRESS_TOTAL} outbound rules" "${regx}" "${SECURITY_GROUP}"
else
textPass "${regx}: ${SECURITY_GROUP} has ${INGRESS_TOTAL} inbound rules and ${EGRESS_TOTAL} outbound rules" "${regx}" "${SECURITY_GROUP}"
fi
done
done
}

View File

@@ -1,86 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra778="7.78"
CHECK_TITLE_extra778="[extra778] Find VPC security groups with wide-open public IPv4 CIDR ranges (non-RFC1918) "
CHECK_SCORED_extra778="NOT_SCORED"
CHECK_CIS_LEVEL_extra778="EXTRA"
CHECK_SEVERITY_extra778="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra778="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check778="extra778"
CHECK_SERVICENAME_extra778="ec2"
CHECK_RISK_extra778='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra778='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra778='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra778='Infrastructure Security'
extra778(){
CIDR_THRESHOLD=24
RFC1918_REGEX="(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)"
check_cidr() {
local SECURITY_GROUP=$1
local DIRECTION=$2
local DIRECTION_FILTER=""
local REGION=$3
case ${DIRECTION} in
"inbound")
DIRECTION_FILTER="IpPermissions"
;;
"outbound")
DIRECTION_FILTER="IpPermissionsEgress"
;;
esac
CIDR_IP_LIST=$(${AWSCLI} ec2 describe-security-groups \
${PROFILE_OPT} \
--filter "Name=group-id,Values=${SECURITY_GROUP}" \
--query "SecurityGroups[*].${DIRECTION_FILTER}[*].IpRanges[*].CidrIp" \
--region ${REGION} \
--output text 2>&1| xargs )
if [[ $(echo "$CIDR_IP_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
for CIDR_IP in ${CIDR_IP_LIST}; do
if [[ ! ${CIDR_IP} =~ ${RFC1918_REGEX} ]]; then
CIDR=$(echo ${CIDR_IP} | cut -d"/" -f2 | xargs)
# Edge case "0.0.0.0/0" for RDP and SSH are checked already by check41 and check42
if [[ ${CIDR} < ${CIDR_THRESHOLD} && 0 < ${CIDR} ]]; then
textFail "${REGION}: ${SECURITY_GROUP} has potential wide-open non-RFC1918 address ${CIDR_IP} in ${DIRECTION} rule" "${REGION}" "${SECURITY_GROUP}"
else
textPass "${REGION}: ${SECURITY_GROUP} has no potential wide-open non-RFC1918 address" "${REGION}" "${SECURITY_GROUP}"
fi
fi
done
}
for regx in ${REGIONS}; do
SECURITY_GROUP_IDS=$(${AWSCLI} ec2 describe-security-groups \
${PROFILE_OPT} \
--region ${regx} \
--query 'SecurityGroups[*].GroupId' \
--output text 2>&1| xargs )
if [[ $(echo "$SECURITY_GROUP_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
for SECURITY_GROUP in ${SECURITY_GROUP_IDS}; do
check_cidr "${SECURITY_GROUP}" "inbound" "${regx}"
check_cidr "${SECURITY_GROUP}" "outbound" "${regx}"
done
done
}

View File

@@ -1,62 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) 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_extra779="7.79"
CHECK_TITLE_extra779="[extra779] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Elasticsearch/Kibana ports"
CHECK_SCORED_extra779="NOT_SCORED"
CHECK_CIS_LEVEL_extra779="EXTRA"
CHECK_SEVERITY_extra779="High"
CHECK_ASFF_RESOURCE_TYPE_extra779="AwsEc2SecurityGroup"
CHECK_ALTERNATE_check779="extra779"
CHECK_SERVICENAME_extra779="ec2"
CHECK_RISK_extra779='If Security groups are not properly configured the attack surface is increased. '
CHECK_REMEDIATION_extra779='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.'
CHECK_DOC_extra779='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html'
CHECK_CAF_EPIC_extra779='Infrastructure Security'
extra779(){
ES_API_PORT="9200"
ES_DATA_PORT="9300"
ES_KIBANA_PORT="5601"
# Test connectivity and authentication is performed by check extra787
for regx in $REGIONS; do
# crate a list of SG open to the world with port $ES_API_PORT or $ES_DATA_PORT or $ES_KIBANA_PORT
SG_LIST=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --output text \
--query "SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=\`$ES_API_PORT\` && ToPort>=\`$ES_API_PORT\`) || (FromPort<=\`$ES_DATA_PORT\` && ToPort>=\`$ES_DATA_PORT\`) || (FromPort<=\`$ES_KIBANA_PORT\` && ToPort>=\`$ES_KIBANA_PORT\`)) && (contains(IpRanges[].CidrIp, \`0.0.0.0/0\`) || contains(Ipv6Ranges[].CidrIpv6, \`::/0\`))]) > \`0\`].{GroupId:GroupId}" 2>&1)
if [[ $(echo "$SG_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe security groups" "$regx"
continue
fi
# in case of open security groups goes through each one
if [[ $SG_LIST ]];then
for sg in $SG_LIST;do
# temp file store the list of instances IDs and public IP address if found
TEMP_EXTRA779_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.EXTRA779.XXXXXXXXXX)
# finds instances with that open security group attached and get its public ip address (if it has one)
$AWSCLI $PROFILE_OPT --region $regx ec2 describe-instances --filters Name=instance.group-id,Values=$sg --query 'Reservations[*].Instances[*].[InstanceId,PublicIpAddress]' --output text > $TEMP_EXTRA779_FILE
# in case of exposed instances it does access checks
if [[ -s "$TEMP_EXTRA779_FILE" ]];then
while read instance eip ; do
if [[ "$eip" == "None" ]];then
textInfo "$regx: Found instance $instance with private IP on Security Group: $sg" "$regx"
else
textFail "$regx: Found instance $instance with public IP $eip on Security Group: $sg open to 0.0.0.0/0 on for Elasticsearch/Kibana ports - use extra787 to test AUTH" "$regx" "$sg"
fi
done < <(cat $TEMP_EXTRA779_FILE)
fi
rm -rf $TEMP_EXTRA779_FILE
done
else
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Elasticsearch/Kibana ports" "$regx"
fi
done
}

View File

@@ -1,63 +0,0 @@
#!/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.
CHECK_ID_extra786="7.86"
CHECK_TITLE_extra786="[extra786] Check if EC2 Instance Metadata Service Version 2 (IMDSv2) is Enabled and Required "
CHECK_SCORED_extra786="NOT_SCORED"
CHECK_CIS_LEVEL_extra786="EXTRA"
CHECK_SEVERITY_extra786="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra786="AwsEc2Instance"
CHECK_ALTERNATE_check786="extra786"
CHECK_SERVICENAME_extra786="ec2"
CHECK_RISK_extra786='Using IMDSv2 will protect from misconfiguration and SSRF vulnerabilities. IMDSv1 will not.'
CHECK_REMEDIATION_extra786='If you dont need IMDS you can turn it off. Using aws-cli you can force the instance to use only IMDSv2.'
CHECK_DOC_extra786='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#configuring-instance-metadata-options'
CHECK_CAF_EPIC_extra786='Infrastructure Security'
extra786(){
for regx in $REGIONS; do
TEMP_EXTRA786_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.EXTRA786.XXXXXXXXXX)
$AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx \
--query 'Reservations[*].Instances[*].{HttpTokens:MetadataOptions.HttpTokens,HttpEndpoint:MetadataOptions.HttpEndpoint,InstanceId:InstanceId}' \
--output text --max-items $MAXITEMS > $TEMP_EXTRA786_FILE 2>&1
if [[ $(cat $TEMP_EXTRA786_FILE | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe instances" "$regx"
continue
fi
# if the file contains data, there are instances in that region
if [[ -s "$TEMP_EXTRA786_FILE" ]];then
# here we read content from the file fields instanceid httptokens_status httpendpoint
while read httpendpoint httptokens_status instanceid ; do
#echo i:$instanceid tok:$httptokens_status end:$httpendpoint
if [[ "$httpendpoint" == "enabled" && "$httptokens_status" == "required" ]];then
textPass "$regx: EC2 Instance $instanceid has IMDSv2 enabled and required" "$regx" "$instanceid"
elif [[ "$httpendpoint" == "disabled" ]];then
textInfo "$regx: EC2 Instance $instanceid has HTTP endpoint access to metadata service disabled" "$regx"
else
textFail "$regx: EC2 Instance $instanceid has IMDSv2 disabled or not required" "$regx" "$instanceid"
fi
done < <(cat $TEMP_EXTRA786_FILE)
else
textInfo "$regx: no EC2 Instances found" "$regx"
fi
rm -fr $TEMP_EXTRA786_FILE
done
}
# Remediation:
# aws ec2 modify-instance-metadata-options \
# --instance-id i-1234567898abcdef0 \
# --http-tokens required \
# --http-endpoint enabled
# More information here https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_ami_public",
"CheckTitle": "Ensure there are no EC2 AMIs set as Public.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "ami",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "critical",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure there are no EC2 AMIs set as Public.",
"Risk": "A shared AMI is an AMI that a developer created and made available for other developers to use. If AMIs have embebed information about the environment could pose a security risk. You use a shared AMI at your own risk. Amazon can not vouch for the integrity or security of AMIs shared by Amazon EC2 users.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "https://docs.bridgecrew.io/docs/public_8#cli-command",
"NativeIaC": "",
"Other": "https://docs.bridgecrew.io/docs/public_8#aws-console",
"Terraform": ""
},
"Recommendation": {
"Text": "List all shared AMIs and make sure there is a business reason for them.",
"Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingsharedamis-finding.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,21 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_ami_public(Check):
def execute(self):
findings = []
for image in ec2_client.images:
report = Check_Report(self.metadata)
report.region = image.region
report.resource_id = image.id
report.status = "PASS"
report.status_extended = f"EC2 AMI {image.id} is not public."
if image.public:
report.status = "FAIL"
report.status_extended = f"EC2 AMI {image.id} is currently public."
report.resource_id = image.id
findings.append(report)
return findings

View File

@@ -0,0 +1,110 @@
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_ami_public:
@mock_ec2
def test_no_amis(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ami_public.ec2_ami_public.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ami_public.ec2_ami_public import (
ec2_ami_public,
)
check = ec2_ami_public()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_one_private_ami(self):
ec2 = client("ec2", region_name="us-east-1")
reservation = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1)
instance = reservation["Instances"][0]
instance_id = instance["InstanceId"]
image_id = ec2.create_image(
InstanceId=instance_id, Name="test-ami", Description="this is a test ami"
)["ImageId"]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ami_public.ec2_ami_public.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_ami_public.ec2_ami_public import (
ec2_ami_public,
)
check = ec2_ami_public()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].status_extended == f"EC2 AMI {image_id} is not public."
assert result[0].resource_id == image_id
@mock_ec2
def test_one_public_ami(self):
ec2 = client("ec2", region_name="us-east-1")
reservation = ec2.run_instances(ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1)
instance = reservation["Instances"][0]
instance_id = instance["InstanceId"]
image_id = ec2.create_image(
InstanceId=instance_id, Name="test-ami", Description="this is a test ami"
)["ImageId"]
image = resource("ec2", region_name="us-east-1").Image(image_id)
ADD_GROUP_ARGS = {
"ImageId": image_id,
"Attribute": "launchPermission",
"OperationType": "add",
"UserGroups": ["all"],
}
image.modify_attribute(**ADD_GROUP_ARGS)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ami_public.ec2_ami_public.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_ami_public.ec2_ami_public import (
ec2_ami_public,
)
check = ec2_ami_public()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended == f"EC2 AMI {image_id} is currently public."
)
assert result[0].resource_id == image_id

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_ebs_default_encryption",
"CheckTitle": "Check if EBS Default Encryption is activated.",
"CheckType": ["Data Protection"],
"ServiceName": "ec2",
"SubServiceName": "ebs",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "Other",
"Description": "Check if EBS Default Encryption is activated.",
"Risk": "If not enabled sensitive information at rest is not protected.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws ec2 enable-ebs-encryption-by-default",
"NativeIaC": "",
"Other": "https://docs.bridgecrew.io/docs/ensure-ebs-default-encryption-is-enabled#aws-console",
"Terraform": "https://docs.bridgecrew.io/docs/ensure-ebs-default-encryption-is-enabled#terraform"
},
"Recommendation": {
"Text": "Enable Encryption. Use a CMK where possible. It will provide additional management and privacy benefits.",
"Url": "https://aws.amazon.com/premiumsupport/knowledge-center/ebs-automatic-encryption/"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,20 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_ebs_default_encryption(Check):
def execute(self):
findings = []
for ebs_encryption in ec2_client.ebs_encryption_by_default:
report = Check_Report(self.metadata)
report.region = ebs_encryption.region
report.resource_id = "EBS Default Encryption"
report.status = "FAIL"
report.status_extended = "EBS Default Encryption is not activated."
if ebs_encryption.status:
report.status = "PASS"
report.status_extended = "EBS Default Encryption is activated."
findings.append(report)
return findings

View File

@@ -0,0 +1,71 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_ebs_default_encryption:
@mock_ec2
def test_ec2_ebs_encryption_enabled(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.enable_ebs_encryption_by_default()
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_default_encryption.ec2_ebs_default_encryption.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_default_encryption.ec2_ebs_default_encryption import (
ec2_ebs_default_encryption,
)
check = ec2_ebs_default_encryption()
results = check.execute()
# One result per region
assert len(results) == 23
for result in results:
if result.region == AWS_REGION:
assert result.status == "PASS"
assert search(
"EBS Default Encryption is activated",
result.status_extended,
)
@mock_ec2
def test_ec2_ebs_encryption_disabled(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_default_encryption.ec2_ebs_default_encryption.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_default_encryption.ec2_ebs_default_encryption import (
ec2_ebs_default_encryption,
)
check = ec2_ebs_default_encryption()
result = check.execute()
# One result per region
assert len(result) == 23
assert result[0].status == "FAIL"
assert search(
"EBS Default Encryption is not activated",
result[0].status_extended,
)

View File

@@ -13,9 +13,9 @@
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"CLI": "https://docs.bridgecrew.io/docs/public_7#cli-command",
"NativeIaC": "",
"Other": "",
"Other": "https://docs.bridgecrew.io/docs/public_7#aws-console",
"Terraform": ""
},
"Recommendation": {

View File

@@ -10,12 +10,12 @@ class ec2_ebs_public_snapshot(Check):
report.region = snapshot.region
if not snapshot.public:
report.status = "PASS"
report.status_extended = f"EBS Snapshot {snapshot.id} is not Public"
report.status_extended = f"EBS Snapshot {snapshot.id} is not Public."
report.resource_id = snapshot.id
else:
report.status = "FAIL"
report.status_extended = (
f"EBS Snapshot {snapshot.id} is currently Public"
f"EBS Snapshot {snapshot.id} is currently Public."
)
report.resource_id = snapshot.id
findings.append(report)

View File

@@ -0,0 +1,108 @@
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_ebs_public_snapshot:
@mock_ec2
def test_ec2_default_snapshots(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot import (
ec2_ebs_public_snapshot,
)
check = ec2_ebs_public_snapshot()
result = check.execute()
# Default snapshots
assert len(result) == 1345
@mock_ec2
def test_ec2_public_snapshot(self):
# Create EC2 Mocked Resources
ec2 = resource("ec2", region_name=AWS_REGION)
ec2_client = client("ec2", region_name=AWS_REGION)
volume = ec2.create_volume(Size=80, AvailabilityZone=f"{AWS_REGION}a")
snapshot = volume.create_snapshot(Description="testsnap")
ec2_client.modify_snapshot_attribute(
SnapshotId=snapshot.id,
Attribute="createVolumePermission",
OperationType="add",
GroupNames=["all"],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot import (
ec2_ebs_public_snapshot,
)
check = ec2_ebs_public_snapshot()
results = check.execute()
# Default snapshots + 1 created
assert len(results) == 1346
for snap in results:
if snap.resource_id == snapshot.id:
assert snap.status == "FAIL"
assert (
snap.status_extended
== f"EBS Snapshot {snapshot.id} is currently Public."
)
@mock_ec2
def test_ec2_private_snapshot(self):
# Create EC2 Mocked Resources
ec2 = resource("ec2", region_name=AWS_REGION)
snapshot = volume = ec2.create_volume(
Size=80, AvailabilityZone=f"{AWS_REGION}a", Encrypted=True
)
snapshot = volume.create_snapshot(Description="testsnap")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot import (
ec2_ebs_public_snapshot,
)
check = ec2_ebs_public_snapshot()
results = check.execute()
# Default snapshots + 1 created
assert len(results) == 1346
for snap in results:
if snap.resource_id == snapshot.id:
assert snap.status == "PASS"
assert (
snap.status_extended
== f"EBS Snapshot {snapshot.id} is not Public."
)

View File

@@ -13,10 +13,10 @@
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
"CLI": "aws ec2 --region <REGION> enable-ebs-encryption-by-default",
"NativeIaC": "https://docs.bridgecrew.io/docs/general_3-encrypt-eps-volume#cloudformation",
"Other": "https://docs.bridgecrew.io/docs/general_3-encrypt-eps-volume#aws-console",
"Terraform": "https://docs.bridgecrew.io/docs/general_3-encrypt-eps-volume#terraform"
},
"Recommendation": {
"Text": "Encrypt all EBS Snapshot and Enable Encryption by default. You can configure your AWS account to enforce the encryption of the new EBS volumes and snapshot copies that you create. For example; Amazon EBS encrypts the EBS volumes created when you launch an instance and the snapshots that you copy from an unencrypted snapshot.",

View File

@@ -10,11 +10,11 @@ class ec2_ebs_snapshots_encrypted(Check):
report.region = snapshot.region
if snapshot.encrypted:
report.status = "PASS"
report.status_extended = f"EBS Snapshot {snapshot.id} is encrypted"
report.status_extended = f"EBS Snapshot {snapshot.id} is encrypted."
report.resource_id = snapshot.id
else:
report.status = "FAIL"
report.status_extended = f"EBS Snapshot {snapshot.id} is unencrypted"
report.status_extended = f"EBS Snapshot {snapshot.id} is unencrypted."
report.resource_id = snapshot.id
findings.append(report)

View File

@@ -0,0 +1,102 @@
from unittest import mock
from boto3 import resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_ebs_snapshots_encrypted:
@mock_ec2
def test_ec2_default_snapshots(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted import (
ec2_ebs_snapshots_encrypted,
)
check = ec2_ebs_snapshots_encrypted()
result = check.execute()
# Default snapshots
assert len(result) == 1345
@mock_ec2
def test_ec2_unencrypted_snapshot(self):
# Create EC2 Mocked Resources
ec2 = resource("ec2", region_name=AWS_REGION)
volume = ec2.create_volume(Size=80, AvailabilityZone=f"{AWS_REGION}a")
snapshot = volume.create_snapshot(Description="testsnap")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted import (
ec2_ebs_snapshots_encrypted,
)
check = ec2_ebs_snapshots_encrypted()
results = check.execute()
# Default snapshots + 1 created
assert len(results) == 1346
for snap in results:
if snap.resource_id == snapshot.id:
assert snap.status == "FAIL"
assert (
snap.status_extended
== f"EBS Snapshot {snapshot.id} is unencrypted."
)
@mock_ec2
def test_ec2_encrypted_snapshot(self):
# Create EC2 Mocked Resources
ec2 = resource("ec2", region_name=AWS_REGION)
snapshot = volume = ec2.create_volume(
Size=80, AvailabilityZone=f"{AWS_REGION}a", Encrypted=True
)
snapshot = volume.create_snapshot(Description="testsnap")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_ebs_snapshots_encrypted.ec2_ebs_snapshots_encrypted import (
ec2_ebs_snapshots_encrypted,
)
check = ec2_ebs_snapshots_encrypted()
results = check.execute()
# Default snapshots + 1 created
assert len(results) == 1346
for snap in results:
if snap.resource_id == snapshot.id:
assert snap.status == "PASS"
assert (
snap.status_extended
== f"EBS Snapshot {snapshot.id} is encrypted."
)

View File

@@ -21,6 +21,7 @@ class ec2_elastic_ip_shodan(Check):
report.status = "FAIL"
report.status_extended = f"Elastic IP {eip.public_ip} listed in Shodan with open ports {str(shodan_info['ports'])} and ISP {shodan_info['isp']} in {shodan_info['country_name']}. More info https://www.shodan.io/host/{eip.public_ip}"
report.resource_id = eip.public_ip
findings.append(report)
except shodan.APIError as error:
if "No information available for that IP" in error.value:
report.status = "PASS"
@@ -32,13 +33,7 @@ class ec2_elastic_ip_shodan(Check):
continue
else:
logger.error(f"Unknown Shodan API Error: {error.value}")
else:
report.status = "PASS"
report.status_extended = (
f"Elastic IP {eip.public_ip} has not a Public IP."
)
report.resource_id = eip.public_ip
findings.append(report)
else:
logger.error(
"ERROR: No Shodan API Key -- Please input a Shodan API Key with -N/--shodan or in config.yaml"

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_elastic_ip_unassgined",
"CheckTitle": "Check if there is any unassigned Elastic IP.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "AwsElasticIPs",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "low",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Check if there is any unassigned Elastic IP.",
"Risk": "Unassigned Elastic IPs may result in extra cost.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws ec2 release-address --public-ip <theIPyoudontneed>",
"NativeIaC": "https://docs.bridgecrew.io/docs/general_19#cloudformation",
"Other": "https://docs.bridgecrew.io/docs/general_19#ec2-console",
"Terraform": "https://docs.bridgecrew.io/docs/general_19#terraform"
},
"Recommendation": {
"Text": "Ensure Elastic IPs are not unassigned.",
"Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,20 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_elastic_ip_unassgined(Check):
def execute(self):
findings = []
for eip in ec2_client.elastic_ips:
report = Check_Report(self.metadata)
report.region = eip.region
if eip.public_ip:
report.resource_id = eip.public_ip
report.status = "FAIL"
report.status_extended = f"Elastic IP {eip.public_ip} is not associated with an instance or network interface."
if eip.association_id:
report.status = "PASS"
report.status_extended = f"Elastic IP {eip.public_ip} is associated with an instance or network interface."
findings.append(report)
return findings

View File

@@ -0,0 +1,105 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_elastic_ip_unassgined:
@mock_ec2
def test_no_eips(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined import (
ec2_elastic_ip_unassgined,
)
check = ec2_elastic_ip_unassgined()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_eip_unassociated(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.allocate_address(Domain="vpc", Address="127.38.43.222")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined import (
ec2_elastic_ip_unassgined,
)
check = ec2_elastic_ip_unassgined()
results = check.execute()
assert len(results) == 1
assert results[0].status == "FAIL"
assert search(
"is not associated",
results[0].status_extended,
)
@mock_ec2
def test_eip_associated(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_resource = resource("ec2", region_name=AWS_REGION)
reservation = ec2_client.run_instances(
ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1
)
instance = ec2_resource.Instance(reservation["Instances"][0]["InstanceId"])
eip = ec2_client.allocate_address(Domain="vpc")
eip = ec2_resource.VpcAddress(eip["AllocationId"])
ec2_client.associate_address(
InstanceId=instance.id, AllocationId=eip.allocation_id
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_elastic_ip_unassgined.ec2_elastic_ip_unassgined import (
ec2_elastic_ip_unassgined,
)
check = ec2_elastic_ip_unassgined()
results = check.execute()
assert len(results) == 1
assert results[0].status == "PASS"
assert search(
"is associated",
results[0].status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_imdsv2_enabled",
"CheckTitle": "Check if EC2 Instance Metadata Service Version 2 (IMDSv2) is Enabled and Required.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsEc2Instance",
"Description": "Check if EC2 Instance Metadata Service Version 2 (IMDSv2) is Enabled and Required.",
"Risk": "Using IMDSv2 will protect from misconfiguration and SSRF vulnerabilities. IMDSv1 will not.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws ec2 modify-instance-metadata-options --instance-id <instance-id> --http-tokens required --http-endpoint enabled",
"NativeIaC": "https://docs.bridgecrew.io/docs/bc_aws_general_31#cloudformation",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/EC2/require-imds-v2.html",
"Terraform": "https://docs.bridgecrew.io/docs/bc_aws_general_31#terraform"
},
"Recommendation": {
"Text": "If you dont need IMDS you can turn it off. Using aws-cli you can force the instance to use only IMDSv2.",
"Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#configuring-instance-metadata-options"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,27 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_instance_imdsv2_enabled(Check):
def execute(self):
findings = []
for instance in ec2_client.instances:
report = Check_Report(self.metadata)
report.region = instance.region
report.resource_id = instance.id
report.status = "FAIL"
report.status_extended = (
f"EC2 Instance {instance.id} has IMDSv2 disabled or not required."
)
if (
instance.http_endpoint == "enabled"
and instance.http_tokens == "required"
):
report.status = "PASS"
report.status_extended = (
f"EC2 Instance {instance.id} has IMDSv2 enabled and required."
)
findings.append(report)
return findings

View File

@@ -0,0 +1,114 @@
from re import search
from unittest import mock
from boto3 import resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_instance_imdsv2_enabled:
@mock_ec2
def test_ec2_no_instances(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled import (
ec2_instance_imdsv2_enabled,
)
check = ec2_instance_imdsv2_enabled()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_one_compliant_ec2(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
MetadataOptions={
"HttpTokens": "required",
"HttpEndpoint": "enabled",
},
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled.ec2_client",
new=EC2(current_audit_info),
) as service_client:
from providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled import (
ec2_instance_imdsv2_enabled,
)
service_client.instances[0].http_endpoint = "enabled"
service_client.instances[0].http_tokens = "required"
check = ec2_instance_imdsv2_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
f"EC2 Instance {instance.id} has IMDSv2 enabled and required",
result[0].status_extended,
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_uncompliant_ec2(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
MetadataOptions={
"HttpTokens": "optional",
"HttpEndpoint": "disabled",
},
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled.ec2_client",
new=EC2(current_audit_info),
) as service_client:
from providers.aws.services.ec2.ec2_instance_imdsv2_enabled.ec2_instance_imdsv2_enabled import (
ec2_instance_imdsv2_enabled,
)
service_client.instances[0].http_endpoint = "disabled"
service_client.instances[0].http_tokens = "optional"
check = ec2_instance_imdsv2_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
f"EC2 Instance {instance.id} has IMDSv2 disabled or not required",
result[0].status_extended,
)
assert result[0].resource_id == instance.id

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_internet_facing_with_instance_profile",
"CheckTitle": "Check for internet facing EC2 instances with Instance Profiles attached.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsEc2Instance",
"Description": "Check for internet facing EC2 instances with Instance Profiles attached.",
"Risk": "Exposing an EC2 directly to internet increases the attack surface and therefore the risk of compromise.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use an ALB and apply WAF ACL.",
"Url": "https://aws.amazon.com/blogs/aws/aws-web-application-firewall-waf-for-application-load-balancers/"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,20 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_instance_internet_facing_with_instance_profile(Check):
def execute(self):
findings = []
for instance in ec2_client.instances:
report = Check_Report(self.metadata)
report.region = instance.region
report.resource_id = instance.id
report.status = "PASS"
report.status_extended = f"EC2 Instance {instance.id} is not internet facing with an instance profile."
if instance.public_ip and instance.instance_profile:
report.status = "FAIL"
report.status_extended = f"EC2 Instance {instance.id} at IP {instance.public_ip} is internet-facing with Instance Profile {instance.instance_profile}."
findings.append(report)
return findings

View File

@@ -0,0 +1,129 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2, mock_iam
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_instance_internet_facing_with_instance_profile:
@mock_ec2
def test_ec2_no_instances(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile import (
ec2_instance_internet_facing_with_instance_profile,
)
check = ec2_instance_internet_facing_with_instance_profile()
result = check.execute()
assert len(result) == 0
@mock_iam
@mock_ec2
def test_one_compliant_ec2(self):
iam = client("iam", "us-west-1")
profile_name = "fake_profile"
_ = iam.create_instance_profile(
InstanceProfileName=profile_name,
)
ec2 = resource("ec2", region_name=AWS_REGION)
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
IamInstanceProfile={"Name": profile_name},
NetworkInterfaces=[
{
"DeviceIndex": 0,
"SubnetId": subnet.id,
"AssociatePublicIpAddress": False,
}
],
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile import (
ec2_instance_internet_facing_with_instance_profile,
)
check = ec2_instance_internet_facing_with_instance_profile()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
f"EC2 Instance {instance.id} is not internet facing with an instance profile",
result[0].status_extended,
)
assert result[0].resource_id == instance.id
@mock_iam
@mock_ec2
def test_one_non_compliant_ec2(self):
iam = client("iam", "us-west-1")
profile_name = "fake_profile"
_ = iam.create_instance_profile(
InstanceProfileName=profile_name,
)
ec2 = resource("ec2", region_name=AWS_REGION)
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
IamInstanceProfile={"Name": profile_name},
NetworkInterfaces=[
{
"DeviceIndex": 0,
"SubnetId": subnet.id,
"AssociatePublicIpAddress": True,
}
],
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_internet_facing_with_instance_profile.ec2_instance_internet_facing_with_instance_profile import (
ec2_instance_internet_facing_with_instance_profile,
)
check = ec2_instance_internet_facing_with_instance_profile()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"is internet-facing with Instance Profile", result[0].status_extended
)
assert result[0].resource_id == instance.id

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_older_than_specific_days",
"CheckTitle": "Check EC2 Instances older than specific days.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsEc2Instance",
"Description": "Check EC2 Instances older than specific days.",
"Risk": "Having old instances within your AWS account could increase the risk of having vulnerable software.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/EC2/ec2-instance-too-old.html",
"Terraform": ""
},
"Recommendation": {
"Text": "Check if software running in the instance is up to date and patched accordingly. Use AWS Systems Manager to patch instances and view patching compliance information.",
"Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/viewing-patch-compliance-results.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,29 @@
from datetime import datetime, timezone
from config.config import get_config_var
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_instance_older_than_specific_days(Check):
def execute(self):
findings = []
max_ec2_instance_age_in_days = get_config_var("max_ec2_instance_age_in_days")
for instance in ec2_client.instances:
report = Check_Report(self.metadata)
report.region = instance.region
report.resource_id = instance.id
report.status = "PASS"
report.status_extended = f"EC2 Instance {instance.id} is not running."
if instance.state == "running":
time_since_launch = (
datetime.now().replace(tzinfo=timezone.utc) - instance.launch_time
)
report.status_extended = f"EC2 Instance {instance.id} is not older than {max_ec2_instance_age_in_days} days ({time_since_launch.days} days)."
if time_since_launch.days > max_ec2_instance_age_in_days:
report.status = "FAIL"
report.status_extended = f"EC2 Instance {instance.id} is older than {max_ec2_instance_age_in_days} days ({time_since_launch.days} days)."
findings.append(report)
return findings

View File

@@ -0,0 +1,106 @@
import datetime
from re import search
from unittest import mock
from boto3 import resource
from dateutil.tz import tzutc
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_instance_older_than_specific_days:
@mock_ec2
def test_ec2_no_instances(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days import (
ec2_instance_older_than_specific_days,
)
check = ec2_instance_older_than_specific_days()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_one_compliant_ec2(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
UserData="This is some user_data",
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days import (
ec2_instance_older_than_specific_days,
)
check = ec2_instance_older_than_specific_days()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
f"EC2 Instance {instance.id} is not older", result[0].status_extended
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_old_ec2(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
UserData="This is some user_data",
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days.ec2_client",
new=EC2(current_audit_info),
) as service_client:
from providers.aws.services.ec2.ec2_instance_older_than_specific_days.ec2_instance_older_than_specific_days import (
ec2_instance_older_than_specific_days,
)
service_client.instances[0].launch_time = datetime.datetime(
2021, 11, 1, 17, 18, tzinfo=tzutc()
)
check = ec2_instance_older_than_specific_days()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
f"EC2 Instance {instance.id} is older", result[0].status_extended
)
assert result[0].resource_id == instance.id

View File

@@ -14,9 +14,9 @@
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
"NativeIaC": "https://docs.bridgecrew.io/docs/public_12#cloudformation",
"Other": "https://docs.bridgecrew.io/docs/public_12#aws-console",
"Terraform": "https://docs.bridgecrew.io/docs/public_12#terraform"
},
"Recommendation": {
"Text": "Use an ALB and apply WAF ACL.",

View File

@@ -10,12 +10,12 @@ class ec2_instance_public_ip(Check):
report.region = instance.region
if instance.public_ip:
report.status = "FAIL"
report.status_extended = f"EC2 instance {instance.id} has a Public IP: {instance.public_ip} ({instance.public_dns})."
report.status_extended = f"EC2 Instance {instance.id} has a Public IP: {instance.public_ip} ({instance.public_dns})."
report.resource_id = instance.id
else:
report.status = "PASS"
report.status_extended = (
f"EC2 instance {instance.id} has not a Public IP."
f"EC2 Instance {instance.id} has not a Public IP."
)
report.resource_id = instance.id
findings.append(report)

View File

@@ -0,0 +1,117 @@
from re import search
from unittest import mock
from boto3 import resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_instance_public_ip:
@mock_ec2
def test_ec2_no_instances(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip import (
ec2_instance_public_ip,
)
check = ec2_instance_public_ip()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_one_compliant_ec2(self):
ec2 = resource("ec2", region_name=AWS_REGION)
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
NetworkInterfaces=[
{
"DeviceIndex": 0,
"SubnetId": subnet.id,
"AssociatePublicIpAddress": False,
}
],
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip import (
ec2_instance_public_ip,
)
check = ec2_instance_public_ip()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
f"EC2 Instance {instance.id} has not a Public IP",
result[0].status_extended,
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_ec2_with_public_ip(self):
ec2 = resource("ec2", region_name=AWS_REGION)
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
NetworkInterfaces=[
{
"DeviceIndex": 0,
"SubnetId": subnet.id,
"AssociatePublicIpAddress": True,
}
],
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_public_ip.ec2_instance_public_ip import (
ec2_instance_public_ip,
)
check = ec2_instance_public_ip()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
f"EC2 Instance {instance.id} has a Public IP", result[0].status_extended
)
assert result[0].resource_id == instance.id

View File

@@ -0,0 +1,36 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_secrets_user_data",
"CheckTitle": "Find secrets in EC2 User Data.",
"CheckType": ["IAM"],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:access-analyzer:region:account-id:analyzer/resource-id",
"Severity": "critical",
"ResourceType": "AwsEc2Instance",
"Description": "Find secrets in EC2 User Data.",
"Risk": "Secrets hardcoded into instance user data can be used by malware and bad actors to gain lateral access to other services.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "https://docs.bridgecrew.io/docs/bc_aws_secrets_1#cli-command",
"NativeIaC": "https://docs.bridgecrew.io/docs/bc_aws_secrets_1#cloudformation",
"Other": "",
"Terraform": "https://docs.bridgecrew.io/docs/bc_aws_secrets_1#terraform"
},
"Recommendation": {
"Text": "Implement automated detective control (e.g. using tools like Prowler) to scan accounts for passwords and secrets. Use secrets manager service to store and retrieve passwords and secrets.",
"Url": "https://docs.aws.amazon.com/secretsmanager/latest/userguide/tutorials_basic.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": [
]
}

View File

@@ -0,0 +1,48 @@
import os
import tempfile
from base64 import b64decode
from detect_secrets import SecretsCollection
from detect_secrets.settings import default_settings
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
class ec2_instance_secrets_user_data(Check):
def execute(self):
findings = []
for instance in ec2_client.instances:
report = Check_Report(self.metadata)
report.region = instance.region
report.resource_id = instance.id
if instance.user_data:
temp_user_data_file = tempfile.NamedTemporaryFile(delete=False)
user_data = b64decode(instance.user_data).decode("utf-8")
temp_user_data_file.write(
bytes(user_data, encoding="raw_unicode_escape")
)
temp_user_data_file.close()
secrets = SecretsCollection()
with default_settings():
secrets.scan_file(temp_user_data_file.name)
if secrets.json():
report.status = "FAIL"
report.status_extended = f"Potential secret found in EC2 instance {instance.id} User Data."
else:
report.status = "PASS"
report.status_extended = (
f"No secrets found in EC2 instance {instance.id} User Data."
)
os.remove(temp_user_data_file.name)
else:
report.status = "PASS"
report.status_extended = f"No secrets found in EC2 instance {instance.id} since User Data is empty."
findings.append(report)
return findings

View File

@@ -0,0 +1,170 @@
from unittest import mock
from boto3 import resource
from moto import mock_ec2
AWS_REGION = "us-east-1"
EXAMPLE_AMI_ID = "ami-12c6146b"
class Test_ec2_instance_secrets_user_data:
@mock_ec2
def test_no_ec2(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data import (
ec2_instance_secrets_user_data,
)
check = ec2_instance_secrets_user_data()
result = check.execute()
assert len(result) == 0
@mock_ec2
def test_one_ec2_with_no_secrets(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
UserData="This is some user_data",
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data import (
ec2_instance_secrets_user_data,
)
check = ec2_instance_secrets_user_data()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"No secrets found in EC2 instance {instance.id} User Data."
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_ec2_with_secrets(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID,
MinCount=1,
MaxCount=1,
UserData="DB_PASSWORD=foobar123",
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data import (
ec2_instance_secrets_user_data,
)
check = ec2_instance_secrets_user_data()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Potential secret found in EC2 instance {instance.id} User Data."
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_ec2_file_with_secrets(self):
# Include launch_configurations to check
f = open(
"providers/aws/services/ec2/ec2_instance_secrets_user_data/fixtures/fixture",
"r",
)
secrets = f.read()
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1, UserData=secrets
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data import (
ec2_instance_secrets_user_data,
)
check = ec2_instance_secrets_user_data()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Potential secret found in EC2 instance {instance.id} User Data."
)
assert result[0].resource_id == instance.id
@mock_ec2
def test_one_launch_configurations_without_user_data(self):
ec2 = resource("ec2", region_name=AWS_REGION)
instance = ec2.create_instances(
ImageId=EXAMPLE_AMI_ID, MinCount=1, MaxCount=1, UserData=""
)[0]
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data.ec2_client",
new=EC2(current_audit_info),
):
from providers.aws.services.ec2.ec2_instance_secrets_user_data.ec2_instance_secrets_user_data import (
ec2_instance_secrets_user_data,
)
check = ec2_instance_secrets_user_data()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"No secrets found in EC2 instance {instance.id} since User Data is empty."
)
assert result[0].resource_id == instance.id

View File

@@ -0,0 +1,4 @@
DB_PASSWORD=foobar123
DB_USER=foo
API_KEY=12345abcd
SERVICE_PASSWORD=bbaabb45

View File

@@ -98,7 +98,6 @@ class Test_ec2_network_acls_allow_ingress_any_port:
assert len(result) == 25
# Search changed sg
for nacl in result:
print(nacl.status)
if nacl.resource_id == nacl_id:
assert nacl.status == "FAIL"
assert (
@@ -144,7 +143,6 @@ class Test_ec2_network_acls_allow_ingress_any_port:
assert len(result) == 25
# Search changed sg
for nacl in result:
print(nacl.status)
if nacl.resource_id == nacl_id:
assert nacl.status == "PASS"
assert (

View File

@@ -0,0 +1,153 @@
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_networkacl_allow_ingress_tcp_port_22:
@mock_ec2
def test_ec2_default_nacls(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22 import (
ec2_networkacl_allow_ingress_tcp_port_22,
)
check = ec2_networkacl_allow_ingress_tcp_port_22()
result = check.execute()
# One default nacl per region
assert len(result) == 23
@mock_ec2
def test_ec2_non_default_compliant_nacl(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22 import (
ec2_networkacl_allow_ingress_tcp_port_22,
)
check = ec2_networkacl_allow_ingress_tcp_port_22()
result = check.execute()
# One default sg per region
assert len(result) == 23
# by default nacls are public
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Network ACL {result[0].resource_id} has SSH port 22 open to the Internet."
)
@mock_ec2
def test_ec2_non_compliant_nacl(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
"NetworkAclId"
]
ec2_client.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=100,
Protocol="6",
PortRange={"From": 22, "To": 22},
RuleAction="allow",
Egress=False,
CidrBlock="0.0.0.0/0",
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22 import (
ec2_networkacl_allow_ingress_tcp_port_22,
)
check = ec2_networkacl_allow_ingress_tcp_port_22()
result = check.execute()
# One default sg per region + default of new VPC + new NACL
assert len(result) == 25
# Search changed sg
for nacl in result:
if nacl.resource_id == nacl_id:
assert nacl.status == "FAIL"
assert (
nacl.status_extended
== f"Network ACL {nacl_id} has SSH port 22 open to the Internet."
)
@mock_ec2
def test_ec2_compliant_nacl(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
"NetworkAclId"
]
ec2_client.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=100,
Protocol="6",
PortRange={"From": 22, "To": 22},
RuleAction="allow",
Egress=False,
CidrBlock="10.0.0.2/32",
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_22.ec2_networkacl_allow_ingress_tcp_port_22 import (
ec2_networkacl_allow_ingress_tcp_port_22,
)
check = ec2_networkacl_allow_ingress_tcp_port_22()
result = check.execute()
# One default sg per region + default of new VPC + new NACL
assert len(result) == 25
# Search changed sg
for nacl in result:
if nacl.resource_id == nacl_id:
assert nacl.status == "PASS"
assert (
nacl.status_extended
== f"Network ACL {nacl_id} has not SSH port 22 open to the Internet."
)

View File

@@ -0,0 +1,153 @@
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_networkacl_allow_ingress_tcp_port_3389:
@mock_ec2
def test_ec2_default_nacls(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389 import (
ec2_networkacl_allow_ingress_tcp_port_3389,
)
check = ec2_networkacl_allow_ingress_tcp_port_3389()
result = check.execute()
# One default nacl per region
assert len(result) == 23
@mock_ec2
def test_ec2_non_default_compliant_nacl(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389 import (
ec2_networkacl_allow_ingress_tcp_port_3389,
)
check = ec2_networkacl_allow_ingress_tcp_port_3389()
result = check.execute()
# One default sg per region
assert len(result) == 23
# by default nacls are public
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Network ACL {result[0].resource_id} has Microsoft RDP port 3389 open to the Internet."
)
@mock_ec2
def test_ec2_non_compliant_nacl(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
"NetworkAclId"
]
ec2_client.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=100,
Protocol="6",
PortRange={"From": 3389, "To": 3389},
RuleAction="allow",
Egress=False,
CidrBlock="0.0.0.0/0",
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389 import (
ec2_networkacl_allow_ingress_tcp_port_3389,
)
check = ec2_networkacl_allow_ingress_tcp_port_3389()
result = check.execute()
# One default sg per region + default of new VPC + new NACL
assert len(result) == 25
# Search changed sg
for nacl in result:
if nacl.resource_id == nacl_id:
assert nacl.status == "FAIL"
assert (
nacl.status_extended
== f"Network ACL {nacl_id} has Microsoft RDP port 3389 open to the Internet."
)
@mock_ec2
def test_ec2_compliant_nacl(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
nacl_id = ec2_client.create_network_acl(VpcId=vpc_id)["NetworkAcl"][
"NetworkAclId"
]
ec2_client.create_network_acl_entry(
NetworkAclId=nacl_id,
RuleNumber=100,
Protocol="6",
PortRange={"From": 3389, "To": 3389},
RuleAction="allow",
Egress=False,
CidrBlock="10.0.0.2/32",
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_networkacl_allow_ingress_tcp_port_3389.ec2_networkacl_allow_ingress_tcp_port_3389 import (
ec2_networkacl_allow_ingress_tcp_port_3389,
)
check = ec2_networkacl_allow_ingress_tcp_port_3389()
result = check.execute()
# One default sg per region + default of new VPC + new NACL
assert len(result) == 25
# Search changed sg
for nacl in result:
if nacl.resource_id == nacl_id:
assert nacl.status == "PASS"
assert (
nacl.status_extended
== f"Network ACL {nacl_id} has not Microsoft RDP port 3389 open to the Internet."
)

View File

@@ -0,0 +1,129 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import (
ec2_securitygroup_allow_ingress_from_internet_to_any_port,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_any_port()
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "-1",
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import (
ec2_securitygroup_allow_ingress_from_internet_to_any_port,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_any_port()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has all ports open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "-1",
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import (
ec2_securitygroup_allow_ingress_from_internet_to_any_port,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_any_port()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not all ports open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018(Check):
def execute(self):
findings = []
check_ports = [27017, 27018]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not MongoDB ports 27017 and 27018 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has MongoDB ports 27017 and 27018 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018 import (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 27017,
"ToPort": 27018,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018 import (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has MongoDB ports 27017 and 27018 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 27017,
"ToPort": 27018,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018.ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018 import (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_port_mongodb_27017_27018()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not MongoDB ports 27017 and 27018 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 20,
"ToPort": 21,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has FTP ports 20 and 21 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 20,
"ToPort": 21,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21.ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_ftp_port_20_21()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not FTP ports 20 and 21 open to the Internet",
sg.status_extended,
)

View File

@@ -13,10 +13,10 @@
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
"CLI": "https://docs.bridgecrew.io/docs/networking_1-port-security#cli-command",
"NativeIaC": "https://docs.bridgecrew.io/docs/networking_1-port-security#cloudformation",
"Other": "https://docs.bridgecrew.io/docs/networking_1-port-security#aws-console",
"Terraform": "https://docs.bridgecrew.io/docs/networking_1-port-security#terraform"
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",

View File

@@ -17,7 +17,7 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22(Check):
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the SSH port 22 open to the Internet."
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has SSH port 22 open to the Internet."
break
findings.append(report)

View File

@@ -0,0 +1,133 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22()
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has SSH port 22 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not SSH port 22 open to the Internet",
sg.status_extended,
)

View File

@@ -13,10 +13,10 @@
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
"CLI": "https://docs.bridgecrew.io/docs/networking_2#cli-command",
"NativeIaC": "https://docs.bridgecrew.io/docs/networking_2#cloudformation",
"Other": "https://docs.bridgecrew.io/docs/networking_2#aws-console",
"Terraform": "https://docs.bridgecrew.io/docs/networking_2#terraform"
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",

View File

@@ -0,0 +1,133 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389()
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 3389,
"ToPort": 3389,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Microsoft RDP port 3389 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 3389,
"ToPort": 3389,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389,
)
check = ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389()
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Microsoft RDP port 3389 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,26 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888(
Check
):
def execute(self):
findings = []
check_ports = [7199, 9160, 8888]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Casandra ports 7199, 8888 and 9160 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Casandra ports 7199, 8888 and 9160 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 7199,
"ToPort": 9160,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Casandra ports 7199, 8888 and 9160 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 7199,
"ToPort": 9160,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_cassandra_7199_9160_8888()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Casandra ports 7199, 8888 and 9160 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Elasticsearch/Kibana ports.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Elasticsearch/Kibana ports.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,26 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601(
Check
):
def execute(self):
findings = []
check_ports = [9200, 9300, 5601]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Elasticsearch/Kibana ports 9200, 9300 and 5601 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Elasticsearch/Kibana ports 9200, 9300 and 5601 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 5601,
"ToPort": 9300,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Elasticsearch/Kibana ports 9200, 9300 and 5601 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 5601,
"ToPort": 9300,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_elasticsearch_kibana_9200_9300_5601()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Elasticsearch/Kibana ports 9200, 9300 and 5601 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Kafka port 9092.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Kafka port 9092.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092(Check):
def execute(self):
findings = []
check_ports = [9092]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Kafka port 9092 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Kafka port 9092 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,138 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 9092,
"ToPort": 9092,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Kafka port 9092 open to the Internet", sg.status_extended
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 9092,
"ToPort": 9092,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_kafka_9092()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Kafka port 9092 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211(Check):
def execute(self):
findings = []
check_ports = [11211]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Memcached port 11211 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Memcached port 11211 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 11211,
"ToPort": 11211,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Memcached port 11211 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 11211,
"ToPort": 11211,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_memcached_11211()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Memcached port 11211 open to the Internet",
sg.status_extended,
)

View File

@@ -17,7 +17,7 @@ class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306(Check
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the MySQL port 3306 open to the Internet."
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has MySQL port 3306 open to the Internet."
report.resource_id = security_group.id
break
findings.append(report)

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 3306,
"ToPort": 3306,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has MySQL port 3306 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 3306,
"ToPort": 3306,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not MySQL port 3306 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 1521,
"ToPort": 2483,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Oracle ports 1521 and 2483 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 1521,
"ToPort": 2483,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Oracle ports 1521 and 2483 open to the Internet",
sg.status_extended,
)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432",
"CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432.",
"CheckType": ["Infrastructure Security"],
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432.",
"Risk": "If Security groups are not properly configured the attack surface is increased.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.",
"Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.ec2.ec2_client import ec2_client
from providers.aws.services.ec2.lib.security_groups import check_security_group
class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432(Check):
def execute(self):
findings = []
check_ports = [5432]
for security_group in ec2_client.security_groups:
report = Check_Report(self.metadata)
report.region = security_group.region
report.resource_id = security_group.id
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Postgres port 5432 open to the Internet."
# Loop through every security group's ingress rule and check it
for ingress_rule in security_group.ingress_rules:
if check_security_group(ingress_rule, "tcp", check_ports):
report.status = "FAIL"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Postgres port 5432 open to the Internet."
break
findings.append(report)
return findings

View File

@@ -0,0 +1,139 @@
from re import search
from unittest import mock
from boto3 import client
from moto import mock_ec2
AWS_REGION = "us-east-1"
class Test_ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432:
@mock_ec2
def test_ec2_default_sgs(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# All are compliant by default
assert result[0].status == "PASS"
@mock_ec2
def test_ec2_non_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 5432,
"ToPort": 5432,
"IpRanges": [{"CidrIp": "0.0.0.0/0"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "FAIL"
assert search(
"has Postgres port 5432 open to the Internet",
sg.status_extended,
)
@mock_ec2
def test_ec2_compliant_default_sg(self):
# Create EC2 Mocked Resources
ec2_client = client("ec2", region_name=AWS_REGION)
ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
default_sg_id = ec2_client.describe_security_groups(GroupNames=["default"])[
"SecurityGroups"
][0]["GroupId"]
ec2_client.authorize_security_group_ingress(
GroupId=default_sg_id,
IpPermissions=[
{
"IpProtocol": "tcp",
"FromPort": 5432,
"ToPort": 5432,
"IpRanges": [{"CidrIp": "123.123.123.123/32"}],
}
],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.ec2.ec2_service import EC2
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_client",
new=EC2(current_audit_info),
):
# Test Check
from providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432.ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432 import (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432,
)
check = (
ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_postgres_5432()
)
result = check.execute()
# One default sg per region
assert len(result) == 24
# Search changed sg
for sg in result:
if sg.resource_id == default_sg_id:
assert sg.status == "PASS"
assert search(
"has not Postgres port 5432 open to the Internet",
sg.status_extended,
)

Some files were not shown because too many files have changed in this diff Show More