From 2b2814723ffc84495f7af928a5f381bed978dd6d Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 24 Jan 2022 13:49:47 +0100 Subject: [PATCH] Prowler 2.7.0 - Brave (#998) * Extra7161 EFS encryption at rest check * Added check_extra7162 which checks if Log groups have 365 days retention * fixed code to handle all regions and formatted output * changed check title, resource type and service name as well as making the code more dynamic * Extra7161 EFS encryption at rest check * New check_extra7163 Secrets Manager key rotation enabled * New check7160 Enabled AutomaticVersionUpgrade on RedShift Cluster * Update ProwlerRole.yaml to have same permissions as util/org-multi-account/ProwlerRole.yaml * Fix link to quicksight dashboard * Install detect-secrets (e.g. for check_extra742) * Updating check_extra7163 with requested changes * fix(assumed-role): Check if -T and -A options are set * docs(Readme): `-T` option is not mandatory * fix(assume-role): Handle AWS STS CLI errors * fix(assume-role): Handle AWS STS CLI errors * Update group25_FTR When trying to run the group 25 (Amazon FTR related security checks) nothing happens, after looking at the code there is a misconfiguration in 2 params: GROUP_RUN_BY_DEFAULT[9] and GROUP_CHECKS[9]. Updating values to 25 fixed the issue. * Update README.md broken link for capital letters in group file (group25_FTR) * #938 issue assume_role multiple times should be fixed * Label 2.7.0-1December2021 for tests * Fixed error that appeared if the number of findings was very high. * Adjusted the batch to only do 50 at a time. 100 caused capacity issues. Also added a check for an edge case where if the updated findings was a multiple of the batch size, it would throw an error for attempting to import 0 findings. * Added line to delete the temp folder after everything is done. * New check 7164 Check if Cloudwatch log groups are protected by AWS KMS@maisenhe * updated CHECK_RISK * Added checks extra7160,extra7161,extra7162,extra7163 to group Extras * Added checks extra7160,extra7161,extra7162,extra7163 to group Extras * Added issue templates * New check 7165 DynamoDB: DAX encrypted at rest @Daniel-Peladeau * New check 7165 DynamoDB: DAX encrypted at rest @Daniel-Peladeau * Fix #963 check 792 to force json in ELB queries * Fix #957 check 763 had us-east-1 region hardcoded * Fix #962 check 7147 ALTERNATE NAME * Fix #940 handling error when can not list functions * Added new checks 7164 and 7165 to group extras * Added invalid check or group id to the error message #962 * Fix Broken Link * Add docker volume example to README.md * Updated Dockerfile to use amazonlinux container * Updated Dockerfile with AWS cli v2 * Added upgrade to the RUN * Added cache purge to Dockerfile * Backup AWS Credentials before AssumeRole and Restore them before CopyToS3 * exporting the ENV variables * fixed bracket * Improved documentation for install process * fix checks with comma issues * Added -D option to copy to S3 with the initial AWS credentials * Cosmetic variable name change * Added $PROFILE_OPT to CopyToS3 commands * remove commas * removed file as it is not needed * Improved help usage options -h * Fixed CIS LEVEL on 7163 through 7165 * When performing a restoreInitialAWSCredentials, unset the credentials ENV variables if they were never set * New check 7166 Elastic IP addresses with associations are protected by AWS Shield Advanced * New check 7167 Cloudfront distributions are protected by AWS Shield Advanced * New check 7168 Route53 hosted zones are protected by AWS Shield Advanced * New check 7169 Global accelerators are protected by AWS Shield Advanced * New check 7170 Application load balancers are protected by AWS Shield Advanced * New check 7171 Classic load balancers are protected by AWS Shield Advanced * Include example for global resources * Add AWS Advance Shield protection checks corrections * Added Shield actions GetSubscriptionState and DescribeProtection * Added Shield actions GetSubscriptionState and DescribeProtection * docs(templates): Improve bug template with more info (#982) * Removed echoes after role chaining fix * Changed Route53 checks7152 and 7153 to INFO when no domains found * Changed Route53 checks 7152 and 7153 title to clarify * Added passed security groups in output to check 778 * Added passed security groups and updated title to check 777 * Added FAIL as error handling when SCP prevents queries to regions * Label version 2.7.0-6January2022 * Updated .dockerignore with .github/ * Fix: issue #758 and #984 * Fix: issue #741 CloudFront and real-time logs * Fix issues #971 set all as INFO instead of FAIL when no access to resource * Fix: issue #986 * Add additional action permissions for Glue and Shield Advanced checks @lazize * Add extra shield action permission Allows the shield:GetSubscriptionState action * Add permission actions Make sure all files where permission actions are necessary will have the same actions * Fix: Credential chaining from environment variables @lazize #996f If profile is not defined, restore original credentials from environment variables, if they exists, before assume-role * Lable version 2.7.0-24January2022 Co-authored-by: Lee Myers Co-authored-by: Chinedu Obiakara Co-authored-by: Daniel Peladeau Co-authored-by: Jonathan Lozano Co-authored-by: Daniel Lorch Co-authored-by: Pepe Fagoaga Co-authored-by: Israel <6672089+lopmoris@users.noreply.github.com> Co-authored-by: root Co-authored-by: nikirby Co-authored-by: Joel Maisenhelder Co-authored-by: RT <35173068+rtcms@users.noreply.github.com> Co-authored-by: Andrea Di Fabio <39841198+sectoramen@users.noreply.github.com> Co-authored-by: Joseph de CLERCK Co-authored-by: Michael Dickinson <45626543+michael-dickinson-sainsburys@users.noreply.github.com> Co-authored-by: Pepe Fagoaga Co-authored-by: Leonardo Azize Martins --- .dockerignore | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 50 ++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++ README.md | 57 +++++---- checks/check119 | 11 +- checks/check122 | 4 +- checks/check21 | 2 +- checks/check22 | 2 +- checks/check23 | 4 +- checks/check24 | 2 +- checks/check25 | 2 +- checks/check26 | 4 +- checks/check27 | 2 +- checks/check28 | 6 +- checks/check29 | 8 +- checks/check41 | 6 +- checks/check42 | 6 +- checks/check43 | 6 +- checks/check44 | 6 +- checks/check45 | 6 +- checks/check46 | 6 +- checks/check_extra710 | 6 +- checks/check_extra7101 | 6 +- checks/check_extra7102 | 6 +- checks/check_extra7103 | 6 +- checks/check_extra7104 | 6 +- checks/check_extra7105 | 6 +- checks/check_extra7106 | 6 +- checks/check_extra7107 | 6 +- checks/check_extra7108 | 6 +- checks/check_extra7109 | 6 +- checks/check_extra711 | 6 +- checks/check_extra7110 | 6 +- checks/check_extra7111 | 6 +- checks/check_extra7112 | 6 +- checks/check_extra7113 | 6 +- checks/check_extra7114 | 6 +- checks/check_extra7115 | 6 +- checks/check_extra7116 | 6 +- checks/check_extra7117 | 6 +- checks/check_extra7118 | 6 +- checks/check_extra7119 | 6 +- checks/check_extra7120 | 6 +- checks/check_extra7121 | 6 +- checks/check_extra7122 | 6 +- checks/check_extra7124 | 6 +- checks/check_extra7127 | 6 +- checks/check_extra7128 | 6 +- checks/check_extra7129 | 6 +- checks/check_extra713 | 2 +- checks/check_extra7130 | 6 +- checks/check_extra7131 | 6 +- checks/check_extra7132 | 6 +- checks/check_extra7133 | 6 +- checks/check_extra7134 | 6 +- checks/check_extra7135 | 6 +- checks/check_extra7136 | 6 +- checks/check_extra7137 | 6 +- checks/check_extra7138 | 6 +- checks/check_extra7139 | 6 +- checks/check_extra714 | 5 +- checks/check_extra7140 | 6 +- checks/check_extra7141 | 6 +- checks/check_extra7142 | 6 +- checks/check_extra7143 | 6 +- checks/check_extra7145 | 6 +- checks/check_extra7146 | 6 +- checks/check_extra7147 | 8 +- checks/check_extra7148 | 6 +- checks/check_extra7149 | 8 +- checks/check_extra715 | 6 +- checks/check_extra7150 | 6 +- checks/check_extra7151 | 6 +- checks/check_extra7152 | 13 +- checks/check_extra7153 | 11 +- checks/check_extra7154 | 6 +- checks/check_extra7155 | 6 +- checks/check_extra7156 | 10 +- checks/check_extra7157 | 6 +- checks/check_extra7158 | 6 +- checks/check_extra7159 | 6 +- checks/check_extra716 | 6 +- checks/check_extra7160 | 46 +++++++ checks/check_extra7161 | 47 +++++++ checks/check_extra7162 | 54 ++++++++ checks/check_extra7163 | 61 +++++++++ checks/check_extra7164 | 61 +++++++++ checks/check_extra7165 | 68 ++++++++++ checks/check_extra7166 | 50 ++++++++ checks/check_extra7167 | 46 +++++++ checks/check_extra7168 | 49 ++++++++ checks/check_extra7169 | 46 +++++++ checks/check_extra717 | 16 ++- checks/check_extra7170 | 48 +++++++ checks/check_extra7171 | 50 ++++++++ checks/check_extra718 | 2 +- checks/check_extra72 | 6 +- checks/check_extra720 | 4 +- checks/check_extra721 | 6 +- checks/check_extra722 | 6 +- checks/check_extra723 | 6 +- checks/check_extra725 | 4 +- checks/check_extra726 | 14 ++- checks/check_extra727 | 8 +- checks/check_extra728 | 6 +- checks/check_extra729 | 6 +- checks/check_extra73 | 12 +- checks/check_extra731 | 8 +- checks/check_extra734 | 6 +- checks/check_extra735 | 6 +- checks/check_extra739 | 6 +- checks/check_extra74 | 6 +- checks/check_extra740 | 17 ++- checks/check_extra741 | 6 +- checks/check_extra742 | 6 +- checks/check_extra743 | 6 +- checks/check_extra744 | 6 +- checks/check_extra745 | 6 +- checks/check_extra746 | 6 +- checks/check_extra747 | 6 +- checks/check_extra748 | 6 +- checks/check_extra749 | 6 +- checks/check_extra75 | 11 +- checks/check_extra750 | 6 +- checks/check_extra751 | 6 +- checks/check_extra752 | 6 +- checks/check_extra753 | 6 +- checks/check_extra754 | 6 +- checks/check_extra755 | 6 +- checks/check_extra757 | 6 +- checks/check_extra758 | 6 +- checks/check_extra759 | 6 +- checks/check_extra76 | 6 +- checks/check_extra760 | 6 +- checks/check_extra761 | 8 +- checks/check_extra762 | 8 +- checks/check_extra763 | 6 +- checks/check_extra764 | 4 +- checks/check_extra765 | 4 +- checks/check_extra768 | 10 +- checks/check_extra769 | 4 +- checks/check_extra77 | 6 +- checks/check_extra770 | 6 +- checks/check_extra772 | 6 +- checks/check_extra775 | 6 +- checks/check_extra776 | 2 +- checks/check_extra777 | 11 +- checks/check_extra778 | 16 ++- checks/check_extra779 | 6 +- checks/check_extra78 | 6 +- checks/check_extra780 | 6 +- checks/check_extra781 | 6 +- checks/check_extra782 | 6 +- checks/check_extra783 | 6 +- checks/check_extra784 | 6 +- checks/check_extra785 | 6 +- checks/check_extra786 | 6 +- checks/check_extra787 | 6 +- checks/check_extra788 | 6 +- checks/check_extra789 | 7 +- checks/check_extra79 | 12 +- checks/check_extra790 | 7 +- checks/check_extra792 | 16 ++- checks/check_extra793 | 12 +- checks/check_extra794 | 8 +- checks/check_extra795 | 6 +- checks/check_extra796 | 6 +- checks/check_extra797 | 6 +- checks/check_extra798 | 6 +- checks/check_sample | 32 ++++- groups/group25_FTR | 4 +- groups/group7_extras | 4 +- iam/create_role_to_assume_cfn.yaml | 4 + iam/prowler-additions-policy.json | 7 +- include/assume_role | 111 +++++++++------- include/aws_profile_loader | 3 +- include/check3x | 2 +- include/outputs_bucket | 20 +-- include/securityhub_integration | 37 ++++-- prowler | 118 ++++++++++-------- util/Dockerfile | 24 +++- .../codebuild-prowler-audit-account-cfn.yaml | 9 +- util/org-multi-account/ProwlerRole.yaml | 2 + .../templates/ProwlerCodeBuildStack.yaml | 6 +- .../templates/ProwlerRole.yaml | 3 + util/terraform-kickstarter/main.tf | 11 +- 186 files changed, 1746 insertions(+), 394 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 checks/check_extra7160 create mode 100644 checks/check_extra7161 create mode 100644 checks/check_extra7162 create mode 100644 checks/check_extra7163 create mode 100644 checks/check_extra7164 create mode 100644 checks/check_extra7165 create mode 100644 checks/check_extra7166 create mode 100644 checks/check_extra7167 create mode 100644 checks/check_extra7168 create mode 100644 checks/check_extra7169 create mode 100644 checks/check_extra7170 create mode 100644 checks/check_extra7171 diff --git a/.dockerignore b/.dockerignore index 58992691..3a5374b0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,5 @@ .git/ +.github/ # Ignore output directories output/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..ead43c3a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,50 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[Bug]: " +labels: ["bug", "triage"] +assignees: '' + +--- + + + +**What happened?** +A clear and concise description of what the bug is or what is not working as expected + + +**How to reproduce it** +Steps to reproduce the behavior: +1. What command are you running? +2. Environment you have, like single account, multi-account, organizations, etc. +3. See error + + +**Expected behavior** +A clear and concise description of what you expected to happen. + + +**Screenshots or Logs** +If applicable, add screenshots to help explain your problem. +Also, you can add logs (anonymize them first!). Here a command that may help to share a log +`bash -x ./prowler -options > debug.log 2>&1` then attach here `debug.log` + + +**From where are you running Prowler?** +Please, complete the following information: + - Resource: [e.g. EC2 instance, Fargate task, Docker container manually, EKS, Cloud9, CodeBuild, workstation, etc.) + - OS: [e.g. Amazon Linux 2, Mac, Alpine, Windows, etc. ] + - AWS-CLI Version [`aws --version`]: + - Prowler Version [`./prowler -V`]: + - Shell and version: + - Others: + + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..11fc491e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/README.md b/README.md index 5cb8afde..a655774f 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Read more about [CIS Amazon Web Services Foundations Benchmark v1.2.0 - 05-23-20 With Prowler you can: - Get a direct colorful or monochrome report -- A HTML, CSV, JUNIT, JSON or JSON ASFF format report +- A HTML, CSV, JUNIT, JSON or JSON ASFF (Security Hub) format report - Send findings directly to Security Hub - Run specific checks and groups or create your own - Check multiple AWS accounts in parallel or sequentially @@ -79,39 +79,47 @@ You can run Prowler from your workstation, an EC2 instance, Fargate or any other ![Prowler high level architecture](https://user-images.githubusercontent.com/3985464/109143232-1488af80-7760-11eb-8d83-726790fda592.jpg) ## Requirements and Installation -Prowler has been written in bash using AWS-CLI and it works in Linux and OSX. +Prowler has been written in bash using AWS-CLI underneath and it works in Linux, Mac OS or Windows with cygwin or virtualization. Also requires `jq` and `detect-secrets` to work properly. -- Make sure the latest version of AWS-CLI is installed on your workstation (it works with either v1 or v2), and other components needed, with Python pip already installed: +- Make sure the latest version of AWS-CLI is installed. It works with either v1 or v2, however _latest v2 is recommended if using new regions since they require STS v2 token_, and other components needed, with Python pip already installed. - ```sh - pip install awscli +- For Amazon Linux (`yum` based Linux distributions and AWS CLI v2): + ``` + sudo yum update -y + sudo yum remove -y awscli + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + unzip awscliv2.zip + sudo ./aws/install + sudo yum install -y python3 jq git + sudo pip3 install detect-secrets==1.0.3 + git clone https://github.com/toniblyx/prowler + ``` +- For Ubuntu Linux (`apt` based Linux distributions and AWS CLI v2): + ``` + sudo apt update + sudo apt install python3 python3-pip jq git zip + pip install detect-secrets==1.0.3 + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + unzip awscliv2.zip + sudo ./aws/install + git clone https://github.com/toniblyx/prowler ``` - > NOTE: detect-secrets Yelp version is no longer supported the one from IBM is mantained now. Use the one mentioned below or the specific Yelp version 1.0.3 to make sure it works as expected (`pip install detect-secrets==1.0.3`): + > NOTE: detect-secrets Yelp version is no longer supported, the one from IBM is mantained now. Use the one mentioned below or the specific Yelp version 1.0.3 to make sure it works as expected (`pip install detect-secrets==1.0.3`): ```sh pip install "git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets" ``` - AWS-CLI can be also installed it using "brew", "apt", "yum" or manually from , but `detect-secrets` has to be installed using `pip` or `pip3`. You will need to install `jq` to get the most from Prowler. + AWS-CLI can be also installed it using other methods, refer to official documentation for more details: , but `detect-secrets` has to be installed using `pip` or `pip3`. -- Make sure jq is installed: examples below with "apt" for Debian alike and "yum" for RedHat alike distros (like Amazon Linux): +- Once Prowler repository is cloned, get into the folder and you can run it: ```sh - sudo apt install jq - ``` - - ```sh - sudo yum install jq - ``` - -- Previous steps, from your workstation: - - ```sh - git clone https://github.com/toniblyx/prowler cd prowler + ./prowler ``` -- Since Prowler users AWS CLI under the hood, you can follow any authentication method as described [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence). Make sure you have properly configured your AWS-CLI with a valid Access Key and Region or declare AWS variables properly (or intance profile): +- Since Prowler users AWS CLI under the hood, you can follow any authentication method as described [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence). Make sure you have properly configured your AWS-CLI with a valid Access Key and Region or declare AWS variables properly (or instance profile/role): ```sh aws configure @@ -150,6 +158,11 @@ Prowler has been written in bash using AWS-CLI and it works in Linux and OSX. docker run -ti --rm --name prowler --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN toniblyx/prowler:latest ``` + In case you want to get reports created by Prowler use docker volume option like in the example below: + ```sh + docker run -ti --rm -v /your/local/output:/prowler/output --name prowler --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN toniblyx/prowler:latest -g hipaa -M csv,json,html + ``` + 1. For custom AWS-CLI profile and region, use the following: (it will use your custom profile and run checks over all regions when needed): ```sh @@ -216,7 +229,7 @@ Prowler has two parameters related to regions: `-r` that is used query AWS servi Prowler html -- Sample screenshot of the Quicksight dashboard, see [https://quicksight-security-dashboard.workshop.aws](quicksight-security-dashboard.workshop.aws/): +- Sample screenshot of the Quicksight dashboard, see [quicksight-security-dashboard.workshop.aws](https://quicksight-security-dashboard.workshop.aws/): Prowler with Quicksight @@ -584,7 +597,7 @@ The `gdpr` group of checks uses existing and extra checks. To get a GDPR report, With this group of checks, Prowler shows result of checks related to the AWS Foundational Technical Review, more information [here](https://apn-checklists.s3.amazonaws.com/foundational/partner-hosted/partner-hosted/CVLHEC5X7.html). The list of checks can be seen in the group file at: -[groups/group25_ftr](groups/group25_ftr) +[groups/group25_ftr](groups/group25_FTR) The `ftr` group of checks uses existing and extra checks. To get a AWS FTR report, run this command: diff --git a/checks/check119 b/checks/check119 index c1ebe209..141a36c2 100644 --- a/checks/check119 +++ b/checks/check119 @@ -27,9 +27,14 @@ CHECK_CAF_EPIC_check119='IAM' check119(){ for regx in $REGIONS; do - EC2_DATA=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[].Instances[].[InstanceId, IamInstanceProfile.Arn, State.Name]' --output json) - EC2_DATA=$(echo $EC2_DATA | jq '.[]|{InstanceId: .[0], ProfileArn: .[1], StateName: .[2]}') - INSTANCE_LIST=$(echo $EC2_DATA | jq -r '.InstanceId') + EC2_DATA=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[].Instances[].[InstanceId, IamInstanceProfile.Arn, State.Name]' --output json 2>&1) + if [[ $(echo "$EC2_DATA" | grep UnauthorizedOperation) ]]; then + textInfo "$regx: Unauthorized Operation error trying to describe instances" "$regx" + continue + else + EC2_DATA=$(echo $EC2_DATA | jq '.[]|{InstanceId: .[0], ProfileArn: .[1], StateName: .[2]}') + INSTANCE_LIST=$(echo $EC2_DATA | jq -r '.InstanceId') + fi if [[ $INSTANCE_LIST ]]; then for instance in $INSTANCE_LIST; do STATE_NAME=$(echo $EC2_DATA | jq -r --arg i "$instance" 'select(.InstanceId==$i)|.StateName') diff --git a/checks/check122 b/checks/check122 index 81ea3e61..db1c68c6 100644 --- a/checks/check122 +++ b/checks/check122 @@ -42,9 +42,9 @@ check122(){ textFail "$REGION: Policy $policy allows \"*:*\"" "$REGION" "$policy" done else - textPass "$REGION: No custom policy found that allow full \"*:*\" administrative privileges" "$REGION" "$policy" + textPass "$REGION: No custom policy found that allow full \"*:*\" administrative privileges" "$REGION" fi else - textPass "$REGION: No custom policies found" "$REGION" "$policy" + textPass "$REGION: No custom policies found" "$REGION" fi } diff --git a/checks/check21 b/checks/check21 index 968f6c19..d34ed292 100644 --- a/checks/check21 +++ b/checks/check21 @@ -32,7 +32,7 @@ check21(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then diff --git a/checks/check22 b/checks/check22 index cca1a8da..98488b2b 100644 --- a/checks/check22 +++ b/checks/check22 @@ -32,7 +32,7 @@ check22(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then diff --git a/checks/check23 b/checks/check23 index 48b9bf44..f8c5fde0 100644 --- a/checks/check23 +++ b/checks/check23 @@ -32,7 +32,7 @@ check23(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -63,7 +63,7 @@ check23(){ # BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $regx --bucket $CLOUDTRAILBUCKET --output text 2>&1) if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then - textFail "Trail $trail in $TRAIL_REGION Access Denied getting bucket location for $CLOUDTRAILBUCKET" + textInfo "Trail $trail in $TRAIL_REGION Access Denied getting bucket location for $CLOUDTRAILBUCKET" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then diff --git a/checks/check24 b/checks/check24 index 68cabd67..9a04d0ae 100644 --- a/checks/check24 +++ b/checks/check24 @@ -32,7 +32,7 @@ check24(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then diff --git a/checks/check25 b/checks/check25 index 752235fc..a1062259 100644 --- a/checks/check25 +++ b/checks/check25 @@ -31,7 +31,7 @@ check25(){ CHECK_AWSCONFIG_RECORDING=$($AWSCLI configservice describe-configuration-recorder-status $PROFILE_OPT --region $regx --query 'ConfigurationRecordersStatus[*].recording' --output text 2>&1) CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice describe-configuration-recorder-status $PROFILE_OPT --region $regx --query 'ConfigurationRecordersStatus[*].lastStatus' --output text 2>&1) if [[ $(echo "$CHECK_AWSCONFIG_STATUS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe configuration recorder status" "$regx" "recorder" + textInfo "$regx: Access Denied trying to describe configuration recorder status" "$regx" "recorder" continue fi if [[ $CHECK_AWSCONFIG_RECORDING == "True" ]]; then diff --git a/checks/check26 b/checks/check26 index 166fbea5..405e6800 100644 --- a/checks/check26 +++ b/checks/check26 @@ -31,7 +31,7 @@ check26(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -62,7 +62,7 @@ check26(){ # BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $regx --bucket $CLOUDTRAILBUCKET --output text 2>&1) if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then - textFail "$regx: Trail $trail Access Denied getting bucket location for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" + textInfo "$regx: Trail $trail Access Denied getting bucket location for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then diff --git a/checks/check27 b/checks/check27 index c5304c74..166b1a07 100644 --- a/checks/check27 +++ b/checks/check27 @@ -32,7 +32,7 @@ check27(){ for regx in $REGIONS; do TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].{Name:TrailARN, HomeRegion:HomeRegion}' --output text 2>&1 | tr " " ',') if [[ $(echo "$TRAILS_AND_REGIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" + textInfo "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then diff --git a/checks/check28 b/checks/check28 index 1008a36d..2770d0a6 100644 --- a/checks/check28 +++ b/checks/check28 @@ -30,7 +30,7 @@ check28(){ for regx in $REGIONS; do CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId' --output text 2>&1) if [[ $(echo "$CHECK_KMS_KEYLIST" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to list keys" "$regx" "$key" + textInfo "$regx: Access Denied trying to list keys" "$regx" "$key" continue fi if [[ $CHECK_KMS_KEYLIST ]]; then @@ -38,7 +38,7 @@ check28(){ for key in $CHECK_KMS_KEYLIST; do KMSDETAILS=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.{key:KeyId,man:KeyManager,origin:Origin,spec:CustomerMasterKeySpec,state:KeyState}' --output text 2>&1 | grep SYMMETRIC) if [[ $(echo "$KMSDETAILS" | grep AccessDenied) ]]; then - textFail "$regx: Key $key Access Denied describing key" "$regx" "$key" + textInfo "$regx: Access Denied describing key $key" "$regx" "$key" continue fi @@ -60,7 +60,7 @@ check28(){ else CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text 2>&1) if [[ $(echo "$CHECK_KMS_KEY_ROTATION" | grep AccessDenied) ]]; then - textFail "$regx: Key $key Access Denied getting key rotation status" "$regx" "$key" + textInfo "$regx: Access Denied getting key rotation status for $key " "$regx" "$key" continue fi if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then diff --git a/checks/check29 b/checks/check29 index dc9f37b4..035fc345 100644 --- a/checks/check29 +++ b/checks/check29 @@ -30,14 +30,14 @@ check29(){ # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" for regx in $REGIONS; do AVAILABLE_VPC=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[?State==`available`].VpcId' --output text 2>&1) - if [[ $(echo "$AVAILABLE_VPC" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe VPCs" "$regx" "$vpcx" + if [[ $(echo "$AVAILABLE_VPC" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe VPCs" "$regx" "$vpcx" continue fi for vpcx in $AVAILABLE_VPC; do CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --filter Name="resource-id",Values="${vpcx}" --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].FlowLogId' --output text 2>&1) - if [[ $(echo "$CHECK_FL" | grep AccessDenied) ]]; then - textFail "$regx: VPC $vpcx Access Denied trying to describe flow logs" "$regx" "$vpcx" + if [[ $(echo "$CHECK_FL" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe flow logs in VPC $vpcx" "$regx" "$vpcx" continue fi if [[ $CHECK_FL ]]; then diff --git a/checks/check41 b/checks/check41 index f8af5e9b..33e87109 100644 --- a/checks/check41 +++ b/checks/check41 @@ -29,7 +29,11 @@ CHECK_CAF_EPIC_check41='Infrastructure Security' check41(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 22 (Scored)" for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && (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') ]]; 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" "$regx" "$SG" diff --git a/checks/check42 b/checks/check42 index cf4b3cf2..71c67838 100644 --- a/checks/check42 +++ b/checks/check42 @@ -29,7 +29,11 @@ CHECK_CAF_EPIC_check42='Infrastructure Security' check42(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389 (Scored)" for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && (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') ]]; 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" "$regx" "$SG" diff --git a/checks/check43 b/checks/check43 index c3a57e12..8e2f004c 100644 --- a/checks/check43 +++ b/checks/check43 @@ -29,7 +29,11 @@ CHECK_CAF_EPIC_check43='Infrastructure Security' check43(){ # "Ensure the default security group of every VPC restricts all traffic (Scored)" for regx in $REGIONS; do - CHECK_SGDEFAULT_IDS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].GroupId[]' --output text) + CHECK_SGDEFAULT_IDS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].GroupId[]' --output text 2>&1) + if [[ $(echo "$CHECK_SGDEFAULT_IDS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe security groups" "$regx" + continue + fi for CHECK_SGDEFAULT_ID in $CHECK_SGDEFAULT_IDS; do CHECK_SGDEFAULT_ID_OPEN=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --group-ids $CHECK_SGDEFAULT_ID --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |egrep '\s0.0.0.0|\:\:\/0') if [[ $CHECK_SGDEFAULT_ID_OPEN ]];then diff --git a/checks/check44 b/checks/check44 index e6b8aee9..158e5c32 100644 --- a/checks/check44 +++ b/checks/check44 @@ -28,7 +28,11 @@ CHECK_CAF_EPIC_check44='Infrastructure Security' check44(){ # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" for regx in $REGIONS; do - LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId'| sort | paste -s -d" " -) + LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId' 2>&1| sort | paste -s -d" " - ) + if [[ $(echo "$LIST_OF_VPCS_PEERING_CONNECTIONS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe vpc peering connections" "$regx" + continue + fi if [[ $LIST_OF_VPCS_PEERING_CONNECTIONS ]];then textInfo "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" "$LIST_OF_VPCS_PEERING_CONNECTIONS" #LIST_OF_VPCS=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[*].VpcId' --output text) diff --git a/checks/check45 b/checks/check45 index c9a461e9..cc95207d 100644 --- a/checks/check45 +++ b/checks/check45 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_check45='Infrastructure Security' check45(){ for regx in $REGIONS; do - NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?(((!PortRange) || (PortRange.From<=`22` && PortRange.To>=`22`)) && ((CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`)))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text) + NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?(((!PortRange) || (PortRange.From<=`22` && PortRange.To>=`22`)) && ((CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`)))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$NACL_LIST" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe vpc network acls" "$regx" + continue + fi if [[ $NACL_LIST ]];then for NACL in $NACL_LIST;do textInfo "$regx: Found Network ACL: $NACL open to 0.0.0.0/0 for SSH port 22" "$regx" "$NACL" diff --git a/checks/check46 b/checks/check46 index 72395991..9bcfccd5 100644 --- a/checks/check46 +++ b/checks/check46 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_check46='Infrastructure Security' check46(){ for regx in $REGIONS; do - NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?(((!PortRange) || (PortRange.From<=`3389` && PortRange.To>=`3389`)) && ((CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`)))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text) + NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?(((!PortRange) || (PortRange.From<=`3389` && PortRange.To>=`3389`)) && ((CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`)))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$NACL_LIST" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe vpc network acls" "$regx" + continue + fi if [[ $NACL_LIST ]];then for NACL in $NACL_LIST;do textInfo "$regx: Found Network ACL: $NACL open to 0.0.0.0/0 for Microsoft RDP port 3389" "$regx" "$NACL" diff --git a/checks/check_extra710 b/checks/check_extra710 index ffd3b035..22bcd7ab 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra710='Infrastructure Security' extra710(){ # "Check for internet facing EC2 Instances " for regx in $REGIONS; do - LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) + LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text 2>&1) + if [[ $(echo "$LIST_OF_PUBLIC_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe instances" "$regx" + continue + fi if [[ $LIST_OF_PUBLIC_INSTANCES ]];then while read -r instance;do INSTANCE_ID=$(echo $instance | awk '{ print $1; }') diff --git a/checks/check_extra7101 b/checks/check_extra7101 index a4fd714c..2efe711a 100644 --- a/checks/check_extra7101 +++ b/checks/check_extra7101 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7101='Logging and Monitoring' extra7101(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do AUDIT_LOGS_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.AUDIT_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) diff --git a/checks/check_extra7102 b/checks/check_extra7102 index f16c3908..f70492c7 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -36,7 +36,11 @@ extra7102(){ textInfo "[extra7102] Requires a Shodan API key to work. Use -N " else for regx in $REGIONS; do - LIST_OF_EIP=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Association.PublicIp' --output text) + 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) diff --git a/checks/check_extra7103 b/checks/check_extra7103 index 12ace203..97713f20 100644 --- a/checks/check_extra7103 +++ b/checks/check_extra7103 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7103='IAM' extra7103(){ for regx in ${REGIONS}; do - LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text) + LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list notebook instances" "$regx" + continue + fi if [[ $LIST_SM_NB_INSTANCES ]];then for nb_instance in $LIST_SM_NB_INSTANCES; do SM_NB_ROOTACCESS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'RootAccess' --output text) diff --git a/checks/check_extra7104 b/checks/check_extra7104 index 7697ad50..c1a44d44 100644 --- a/checks/check_extra7104 +++ b/checks/check_extra7104 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7104='Infrastructure Security' extra7104(){ for regx in ${REGIONS}; do - LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text) + LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list notebook instances" "$regx" + continue + fi if [[ $LIST_SM_NB_INSTANCES ]];then for nb_instance in $LIST_SM_NB_INSTANCES; do SM_NB_SUBNETID=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'SubnetId' --output text) diff --git a/checks/check_extra7105 b/checks/check_extra7105 index 1b2d2c89..5ba8d94d 100644 --- a/checks/check_extra7105 +++ b/checks/check_extra7105 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7105='Infrastructure Security' extra7105(){ for regx in ${REGIONS}; do - LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text) + LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_MODELS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list models" "$regx" + continue + fi if [[ $LIST_SM_NB_MODELS ]];then for nb_model_name in $LIST_SM_NB_MODELS; do SM_NB_NETWORKISOLATION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-model --model-name $nb_model_name --query 'EnableNetworkIsolation' --output text) diff --git a/checks/check_extra7106 b/checks/check_extra7106 index af09f269..9863edf7 100644 --- a/checks/check_extra7106 +++ b/checks/check_extra7106 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7106='Infrastructure Security' extra7106(){ for regx in ${REGIONS}; do - LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text) + LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_MODELS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list models" "$regx" + continue + fi if [[ $LIST_SM_NB_MODELS ]];then for nb_model_name in $LIST_SM_NB_MODELS; do SM_NB_VPCCONFIG=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-model --model-name $nb_model_name --query 'VpcConfig.Subnets' --output text) diff --git a/checks/check_extra7107 b/checks/check_extra7107 index e5536e87..1a94873b 100644 --- a/checks/check_extra7107 +++ b/checks/check_extra7107 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7107='Data Protection' extra7107(){ for regx in ${REGIONS}; do - LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text) + LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list training jobs" "$regx" + continue + fi if [[ $LIST_SM_NB_JOBS ]];then for nb_job_name in $LIST_SM_NB_JOBS; do SM_NB_INTERCONTAINERENCRYPTION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'EnableInterContainerTrafficEncryption' --output text) diff --git a/checks/check_extra7108 b/checks/check_extra7108 index 2956afe8..183cd302 100644 --- a/checks/check_extra7108 +++ b/checks/check_extra7108 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7108='Data Protection' extra7108(){ for regx in ${REGIONS}; do - LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text) + LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list training jobs" "$regx" + continue + fi if [[ $LIST_SM_NB_JOBS ]];then for nb_job_name in $LIST_SM_NB_JOBS; do SM_JOB_KMSENCRYPTION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'ResourceConfig.VolumeKmsKeyId' --output text) diff --git a/checks/check_extra7109 b/checks/check_extra7109 index 90d036e0..8775ee74 100644 --- a/checks/check_extra7109 +++ b/checks/check_extra7109 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7109='Infrastructure Security' extra7109(){ for regx in ${REGIONS}; do - LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text) + LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list training jobs" "$regx" + continue + fi if [[ $LIST_SM_NB_JOBS ]];then for nb_job_name in $LIST_SM_NB_JOBS; do SM_NB_NETWORKISOLATION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'EnableNetworkIsolation' --output text) diff --git a/checks/check_extra711 b/checks/check_extra711 index a7c7b798..2b8335d9 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra711='Data Protection' extra711(){ # "Check for Publicly Accessible Redshift Clusters " for regx in $REGIONS; do - LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text) + LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text 2>&1) + if [[ $(echo "$LIST_OF_PUBLIC_REDSHIFT_CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe clusters" "$regx" + continue + fi if [[ $LIST_OF_PUBLIC_REDSHIFT_CLUSTERS ]];then while read -r cluster;do CLUSTER_ID=$(echo $cluster | awk '{ print $1; }') diff --git a/checks/check_extra7110 b/checks/check_extra7110 index 448e2308..151d35cf 100644 --- a/checks/check_extra7110 +++ b/checks/check_extra7110 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7110='Infrastructure Security' extra7110(){ for regx in ${REGIONS}; do - LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text) + LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list training jobs" "$regx" + continue + fi if [[ $LIST_SM_NB_JOBS ]];then for nb_job_name in $LIST_SM_NB_JOBS; do SM_NB_SUBNETS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'VpcConfig.Subnets' --output text) diff --git a/checks/check_extra7111 b/checks/check_extra7111 index a6669a09..936931fd 100644 --- a/checks/check_extra7111 +++ b/checks/check_extra7111 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7111='Infrastructure Security' extra7111(){ for regx in ${REGIONS}; do - LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text) + LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list notebook instances" "$regx" + continue + fi if [[ $LIST_SM_NB_INSTANCES ]];then for nb_instance in $LIST_SM_NB_INSTANCES; do SM_NB_DIRECTINET=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'DirectInternetAccess' --output text) diff --git a/checks/check_extra7112 b/checks/check_extra7112 index e031065d..c3143cb7 100644 --- a/checks/check_extra7112 +++ b/checks/check_extra7112 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7112='Data Protection' extra7112(){ for regx in ${REGIONS}; do - LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text) + LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1) + if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list notebook instances" "$regx" + continue + fi if [[ $LIST_SM_NB_INSTANCES ]];then for nb_instance in $LIST_SM_NB_INSTANCES; do SM_NB_KMSKEY=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'KmsKeyId' --output text) diff --git a/checks/check_extra7113 b/checks/check_extra7113 index 4afcfdc3..e8e61201 100644 --- a/checks/check_extra7113 +++ b/checks/check_extra7113 @@ -37,7 +37,11 @@ CHECK_CAF_EPIC_extra7113='Data Protection' extra7113(){ for regx in $REGIONS; do - LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text) + LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $LIST_OF_RDS_INSTANCES ]];then for rdsinstance in $LIST_OF_RDS_INSTANCES; do IS_DELETIONPROTECTION=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].DeletionProtection' --output text) diff --git a/checks/check_extra7114 b/checks/check_extra7114 index 91a640bb..9179e63f 100644 --- a/checks/check_extra7114 +++ b/checks/check_extra7114 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7114='Data Protection' extra7114(){ for regx in $REGIONS; do - LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json) + LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json 2>&1) + if [[ $(echo "$LIST_EP_SC" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get dev endpoints" "$regx" + continue + fi if [[ $LIST_EP_SC != '[]' ]]; then for ep in $(echo "${LIST_EP_SC}"| jq -r '.[] | @base64');do ENDPOINT_NAME=$(echo $ep | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7115 b/checks/check_extra7115 index e09e6590..8abca268 100644 --- a/checks/check_extra7115 +++ b/checks/check_extra7115 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7115='Data Protection' extra7115(){ for regx in $REGIONS; do - CONNECTION_LIST=$($AWSCLI glue get-connections $PROFILE_OPT --region $regx --output json --query 'ConnectionList[*].{Name:Name,SSL:ConnectionProperties.JDBC_ENFORCE_SSL}') + CONNECTION_LIST=$($AWSCLI glue get-connections $PROFILE_OPT --region $regx --output json --query 'ConnectionList[*].{Name:Name,SSL:ConnectionProperties.JDBC_ENFORCE_SSL}' 2>&1) + if [[ $(echo "$CONNECTION_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get connections" "$regx" + continue + fi if [[ $CONNECTION_LIST != '[]' ]]; then for connection in $(echo "${CONNECTION_LIST}" | jq -r '.[] | @base64'); do CONNECTION_NAME=$(echo $connection | base64 --decode | jq -r '.Name' ) diff --git a/checks/check_extra7116 b/checks/check_extra7116 index d18ab6f2..4aad3ecb 100644 --- a/checks/check_extra7116 +++ b/checks/check_extra7116 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7116='Data Protection' extra7116(){ for regx in $REGIONS; do - TABLE_LIST=$($AWSCLI glue search-tables --max-results 1 $PROFILE_OPT --region $regx --output text --query 'TableList[*]' ) + TABLE_LIST=$($AWSCLI glue search-tables --max-results 1 $PROFILE_OPT --region $regx --output text --query 'TableList[*]' 2>&1) + if [[ $(echo "$TABLE_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to search tables" "$regx" + continue + fi if [[ ! -z $TABLE_LIST ]]; then METADATA_ENCRYPTED=$($AWSCLI glue get-data-catalog-encryption-settings $PROFILE_OPT --region $regx --output text --query "DataCatalogEncryptionSettings.EncryptionAtRest.CatalogEncryptionMode") if [[ "$METADATA_ENCRYPTED" == "DISABLED" ]]; then diff --git a/checks/check_extra7117 b/checks/check_extra7117 index 6091a71c..c390fcac 100644 --- a/checks/check_extra7117 +++ b/checks/check_extra7117 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7117='Data Protection' extra7117(){ for regx in $REGIONS; do - CONNECTION_LIST=$($AWSCLI glue get-connections $PROFILE_OPT --region $regx --output text --query 'ConnectionList[*]') + CONNECTION_LIST=$($AWSCLI glue get-connections $PROFILE_OPT --region $regx --output text --query 'ConnectionList[*]' 2>&1) + if [[ $(echo "$CONNECTION_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get connections" "$regx" + continue + fi if [[ ! -z $CONNECTION_LIST ]]; then METADATA_ENCRYPTED=$($AWSCLI glue get-data-catalog-encryption-settings $PROFILE_OPT --region $regx --output text --query "DataCatalogEncryptionSettings.ConnectionPasswordEncryption.ReturnConnectionPasswordEncrypted") if [[ "$METADATA_ENCRYPTED" == "False" ]]; then diff --git a/checks/check_extra7118 b/checks/check_extra7118 index 0b70fcab..53303c08 100644 --- a/checks/check_extra7118 +++ b/checks/check_extra7118 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7118='Data Protection' extra7118(){ for regx in $REGIONS; do - JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration,JobEncryption:DefaultArguments."--encryption-type"}') + JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration,JobEncryption:DefaultArguments."--encryption-type"}' 2>&1) + if [[ $(echo "$JOB_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get jobs" "$regx" + continue + fi if [[ $JOB_LIST != '[]' ]]; then for job in $(echo "${JOB_LIST}" | jq -r '.[] | @base64'); do JOB_NAME=$(echo $job | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7119 b/checks/check_extra7119 index a3ca4a10..06270736 100644 --- a/checks/check_extra7119 +++ b/checks/check_extra7119 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7119='Logging and Monitoring' extra7119(){ for regx in $REGIONS; do - LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json) + LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json 2>&1) + if [[ $(echo "$LIST_EP_SC" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get dev endpoints" "$regx" + continue + fi if [[ $LIST_EP_SC != '[]' ]]; then for ep in $(echo "${LIST_EP_SC}"| jq -r '.[] | @base64');do ENDPOINT_NAME=$(echo $ep | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7120 b/checks/check_extra7120 index 93907c93..018067c5 100644 --- a/checks/check_extra7120 +++ b/checks/check_extra7120 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7120='Logging and Monitoring' extra7120(){ for regx in $REGIONS; do - JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration}') + JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration}' 2>&1) + if [[ $(echo "$JOB_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get jobs" "$regx" + continue + fi if [[ $JOB_LIST != '[]' ]]; then for job in $(echo "${JOB_LIST}" | jq -r '.[] | @base64'); do JOB_NAME=$(echo $job | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7121 b/checks/check_extra7121 index 13259770..bdc041d1 100644 --- a/checks/check_extra7121 +++ b/checks/check_extra7121 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7121='Data Protection' extra7121(){ for regx in $REGIONS; do - LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json) + LIST_EP_SC=$($AWSCLI glue get-dev-endpoints $PROFILE_OPT --region $regx --query 'DevEndpoints[*].{Name:EndpointName,Security:SecurityConfiguration}' --output json 2>&1) + if [[ $(echo "$LIST_EP_SC" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get dev endpoints" "$regx" + continue + fi if [[ $LIST_EP_SC != '[]' ]]; then for ep in $(echo "${LIST_EP_SC}"| jq -r '.[] | @base64');do ENDPOINT_NAME=$(echo $ep | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7122 b/checks/check_extra7122 index 9f50bb71..6c91dfca 100644 --- a/checks/check_extra7122 +++ b/checks/check_extra7122 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7122='Data Protection' extra7122(){ for regx in $REGIONS; do - JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration}') + JOB_LIST=$($AWSCLI glue get-jobs $PROFILE_OPT --region $regx --output json --query 'Jobs[*].{Name:Name,SecurityConfiguration:SecurityConfiguration}' 2>&1) + if [[ $(echo "$JOB_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get jobs" "$regx" + continue + fi if [[ $JOB_LIST != '[]' ]]; then for job in $(echo "${JOB_LIST}" | jq -r '.[] | @base64'); do JOB_NAME=$(echo $job | base64 --decode | jq -r '.Name') diff --git a/checks/check_extra7124 b/checks/check_extra7124 index 7a7e8b1f..72b1e1c1 100644 --- a/checks/check_extra7124 +++ b/checks/check_extra7124 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra7124='Infrastructure Security' extra7124(){ for regx in $REGIONS; do # Filters running instances only - LIST_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --query 'Reservations[*].Instances[*].[InstanceId]' --filters Name=instance-state-name,Values=running --region $regx --output text) + LIST_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --query 'Reservations[*].Instances[*].[InstanceId]' --filters Name=instance-state-name,Values=running --region $regx --output text 2>&1) + if [[ $(echo "$LIST_EC2_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe instances" "$regx" + continue + fi if [[ $LIST_EC2_INSTANCES ]]; then LIST_SSM_MANAGED_INSTANCES=$($AWSCLI ssm describe-instance-information $PROFILE_OPT --query "InstanceInformationList[].InstanceId" --region $regx | jq -r '.[]') LIST_EC2_UNMANAGED=$(echo ${LIST_SSM_MANAGED_INSTANCES[@]} ${LIST_EC2_INSTANCES[@]} | tr ' ' '\n' | sort | uniq -u) diff --git a/checks/check_extra7127 b/checks/check_extra7127 index 9c12009a..34650167 100644 --- a/checks/check_extra7127 +++ b/checks/check_extra7127 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra7127='Infrastructure Security' extra7127(){ for regx in $REGIONS; do - NON_COMPLIANT_SSM_MANAGED_INSTANCES=$($AWSCLI ssm list-resource-compliance-summaries $PROFILE_OPT --region $regx --filters Key=Status,Values=NON_COMPLIANT --query ResourceComplianceSummaryItems[].ResourceId --output text) + NON_COMPLIANT_SSM_MANAGED_INSTANCES=$($AWSCLI ssm list-resource-compliance-summaries $PROFILE_OPT --region $regx --filters Key=Status,Values=NON_COMPLIANT --query ResourceComplianceSummaryItems[].ResourceId --output text 2>&1) + if [[ $(echo "$NON_COMPLIANT_SSM_MANAGED_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list resource compliance summaries" "$regx" + continue + fi COMPLIANT_SSM_MANAGED_INSTANCES=$($AWSCLI ssm list-resource-compliance-summaries $PROFILE_OPT --region $regx --filters Key=Status,Values=COMPLIANT --query ResourceComplianceSummaryItems[].ResourceId --output text) if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES || $COMPLIANT_SSM_MANAGED_INSTANCES ]]; then if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES ]]; then diff --git a/checks/check_extra7128 b/checks/check_extra7128 index f9ad2cda..61c7f6e3 100644 --- a/checks/check_extra7128 +++ b/checks/check_extra7128 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7128='Data Protection' extra7128(){ for regx in $REGIONS; do - DDB_TABLES_LIST=$($AWSCLI dynamodb list-tables $PROFILE_OPT --region $regx --output text --query TableNames) + DDB_TABLES_LIST=$($AWSCLI dynamodb list-tables $PROFILE_OPT --region $regx --output text --query TableNames 2>&1) + if [[ $(echo "$DDB_TABLES_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list tables" "$regx" + continue + fi if [[ $DDB_TABLES_LIST ]]; then for table in $DDB_TABLES_LIST; do DDB_TABLE_WITH_KMS=$($AWSCLI dynamodb describe-table --table-name $table $PROFILE_OPT --region $regx --query Table.SSEDescription.SSEType --output text) diff --git a/checks/check_extra7129 b/checks/check_extra7129 index caa6fefa..29031a6c 100644 --- a/checks/check_extra7129 +++ b/checks/check_extra7129 @@ -29,7 +29,11 @@ PARALLEL_REGIONS="50" extra7129(){ for regx in $REGIONS; do # ( - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing` && Type == `application`].[LoadBalancerName]' --output text) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing` && Type == `application`].[LoadBalancerName]' --output text 2>&1) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi LIST_OF_WAFV2_WEBACL_ARN=$($AWSCLI wafv2 list-web-acls $PROFILE_OPT --region=$regx --scope=REGIONAL --query WebACLs[*].ARN --output text) LIST_OF_WAFV1_WEBACL_WEBACLID=$($AWSCLI waf-regional list-web-acls $PROFILE_OPT --region $regx --query WebACLs[*].[WebACLId] --output text) diff --git a/checks/check_extra713 b/checks/check_extra713 index 01f96d58..17b56827 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -44,7 +44,7 @@ extra713(){ fi else # if list-detectors return any error - textInfo "$regx: GuardDuty not checked" "$regx" + textInfo "$regx: GuardDuty not checked or Access Denied trying to get detector" "$regx" fi done } \ No newline at end of file diff --git a/checks/check_extra7130 b/checks/check_extra7130 index f1641516..0980eea9 100644 --- a/checks/check_extra7130 +++ b/checks/check_extra7130 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7130='Data Protection' extra7130(){ for regx in $REGIONS; do - LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query 'Topics[*].TopicArn' --output text) + LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query 'Topics[*].TopicArn' --output text 2>&1) + if [[ $(echo "$LIST_SNS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list topics" "$regx" + continue + fi if [[ $LIST_SNS ]];then for topic in $LIST_SNS; do SHORT_TOPIC=$(echo $topic | awk -F ":" '{print $NF}') diff --git a/checks/check_extra7131 b/checks/check_extra7131 index dbd22bd9..af4bc429 100644 --- a/checks/check_extra7131 +++ b/checks/check_extra7131 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7131='Infrastructure Security' extra7131(){ for regx in $REGIONS; do # LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true` && DBInstanceStatus==`"available"`].[DBInstanceIdentifier,Endpoint.Address]' --output text) - LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].[DBInstanceIdentifier,AutoMinorVersionUpgrade]' --output text) + LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].[DBInstanceIdentifier,AutoMinorVersionUpgrade]' --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $LIST_OF_RDS_INSTANCES ]];then while read -r rds_instance;do RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') diff --git a/checks/check_extra7132 b/checks/check_extra7132 index 4d3af561..a2bbba74 100644 --- a/checks/check_extra7132 +++ b/checks/check_extra7132 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7132='Logging and Monitoring' extra7132(){ for regx in $REGIONS; do - RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text) + RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text 2>&1) + if [[ $(echo "$RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $RDS_INSTANCES ]];then for rdsinstance in ${RDS_INSTANCES}; do RDS_NAME="$rdsinstance" diff --git a/checks/check_extra7133 b/checks/check_extra7133 index ee20f261..eae0f3a0 100644 --- a/checks/check_extra7133 +++ b/checks/check_extra7133 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7133='Data Protection' extra7133(){ for regx in $REGIONS; do - RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text) + RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text 2>&1) + if [[ $(echo "$RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $RDS_INSTANCES ]];then for rdsinstance in ${RDS_INSTANCES}; do RDS_NAME="$rdsinstance" diff --git a/checks/check_extra7134 b/checks/check_extra7134 index 14f2b957..4919262f 100644 --- a/checks/check_extra7134 +++ b/checks/check_extra7134 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7134='Infrastructure Security' extra7134(){ for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`20` && ToPort==`21`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`20` && ToPort==`21`)) && (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 FTP ports" "$regx" "$SG" diff --git a/checks/check_extra7135 b/checks/check_extra7135 index 2788b54e..74c9cb74 100644 --- a/checks/check_extra7135 +++ b/checks/check_extra7135 @@ -25,7 +25,11 @@ 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) + 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" diff --git a/checks/check_extra7136 b/checks/check_extra7136 index b7779b6f..3646a827 100644 --- a/checks/check_extra7136 +++ b/checks/check_extra7136 @@ -25,7 +25,11 @@ 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) + 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" diff --git a/checks/check_extra7137 b/checks/check_extra7137 index 5759927e..00afed61 100644 --- a/checks/check_extra7137 +++ b/checks/check_extra7137 @@ -25,7 +25,11 @@ 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) + 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" diff --git a/checks/check_extra7138 b/checks/check_extra7138 index f164aa62..14b05ebb 100644 --- a/checks/check_extra7138 +++ b/checks/check_extra7138 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7138='Infrastructure Security' extra7138(){ for regx in $REGIONS; do - NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?((!PortRange) && (CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text) + NACL_LIST=$($AWSCLI ec2 describe-network-acls --query 'NetworkAcls[?Entries[?((!PortRange) && (CidrBlock == `0.0.0.0/0`) && (Egress == `false`) && (RuleAction == `allow`))]].{NetworkAclId:NetworkAclId}' $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$NACL_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe network acls" "$regx" + continue + fi if [[ $NACL_LIST ]];then for NACL in $NACL_LIST;do textInfo "$regx: Found Network ACL: $NACL open to 0.0.0.0/0 for any port" "$regx" "$NACL" diff --git a/checks/check_extra7139 b/checks/check_extra7139 index 094037ee..4268c26f 100644 --- a/checks/check_extra7139 +++ b/checks/check_extra7139 @@ -25,7 +25,11 @@ extra7139(){ for regx in $REGIONS; do DETECTORS_LIST="" - DETECTORS_LIST=$($AWSCLI guardduty list-detectors --query DetectorIds $PROFILE_OPT --region $regx --output text) + DETECTORS_LIST=$($AWSCLI guardduty list-detectors --query DetectorIds $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$DETECTORS_LIST" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list detectors" "$regx" + continue + fi if [[ $DETECTORS_LIST ]];then for DETECTOR in $DETECTORS_LIST;do FINDINGS_COUNT="" diff --git a/checks/check_extra714 b/checks/check_extra714 index 40d2c679..9408fa6d 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -28,8 +28,9 @@ extra714(){ LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --query 'DistributionList.Items[].Id' --output text | grep -v "^None") if [[ $LIST_OF_DISTRIBUTIONS ]]; then for dist in $LIST_OF_DISTRIBUTIONS; do - LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --id "$dist" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true) - if [[ $LOG_ENABLED ]]; then + LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --id "$dist" --query 'Distribution.DistributionConfig.Logging.Enabled' --output text | grep True) + LOG_ENABLED_REALTIME=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --id "$dist" --query 'Distribution.DistributionConfig.DefaultCacheBehavior.RealtimeLogConfigArn' --output text | grep -i arn) + if [[ $LOG_ENABLED || $LOG_ENABLED_REALTIME ]]; then textPass "$REGION: CloudFront distribution $dist has logging enabled" "$REGION" "$dist" else textFail "$REGION: CloudFront distribution $dist has logging disabled" "$REGION" "$dist" diff --git a/checks/check_extra7140 b/checks/check_extra7140 index 42f93e72..3cab4570 100644 --- a/checks/check_extra7140 +++ b/checks/check_extra7140 @@ -24,7 +24,11 @@ CHECK_CAF_EPIC_extra7140='Data Protection' extra7140(){ for regx in $REGIONS; do - SSM_DOCS=$($AWSCLI $PROFILE_OPT --region $regx ssm list-documents --filters Key=Owner,Values=Self --query DocumentIdentifiers[].Name --output text) + SSM_DOCS=$($AWSCLI $PROFILE_OPT --region $regx ssm list-documents --filters Key=Owner,Values=Self --query DocumentIdentifiers[].Name --output text 2>&1) + if [[ $(echo "$SSM_DOCS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list documents" "$regx" + continue + fi if [[ $SSM_DOCS ]];then for ssmdoc in $SSM_DOCS; do SSM_DOC_SHARED_ALL=$($AWSCLI $PROFILE_OPT --region $regx ssm describe-document-permission --name "$ssmdoc" --permission-type "Share" --query AccountIds[] --output text | grep all) diff --git a/checks/check_extra7141 b/checks/check_extra7141 index 3b828cdd..1768b4fc 100644 --- a/checks/check_extra7141 +++ b/checks/check_extra7141 @@ -31,7 +31,11 @@ extra7141(){ fi for regx in $REGIONS; do - SSM_DOCS=$($AWSCLI $PROFILE_OPT --region $regx ssm list-documents --filters Key=Owner,Values=Self --query DocumentIdentifiers[].Name --output text) + SSM_DOCS=$($AWSCLI $PROFILE_OPT --region $regx ssm list-documents --filters Key=Owner,Values=Self --query DocumentIdentifiers[].Name --output text 2>&1) + if [[ $(echo "$SSM_DOCS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list documents" "$regx" + continue + fi if [[ $SSM_DOCS ]];then for ssmdoc in $SSM_DOCS; do SSM_DOC_FILE="$SECRETS_TEMP_FOLDER/extra7141-$ssmdoc-$regx-content.txt" diff --git a/checks/check_extra7142 b/checks/check_extra7142 index 9900d46d..ded331ec 100644 --- a/checks/check_extra7142 +++ b/checks/check_extra7142 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra7142='Data Protection' extra7142(){ for regx in $REGIONS; do - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text 2>&1) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBSV2 ]];then for alb in $LIST_OF_ELBSV2;do CHECK_IF_DROP_INVALID_HEADER_FIELDS=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $alb --query 'Attributes[6]' --output text|grep -i true) diff --git a/checks/check_extra7143 b/checks/check_extra7143 index 7d3ee0eb..abf1d81f 100644 --- a/checks/check_extra7143 +++ b/checks/check_extra7143 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7143='Data Protection' extra7143(){ # "Check if EFS have policies which allow access to everyone (Not Scored) (Not part of CIS benchmark)" for regx in $REGIONS; do - LIST_OF_EFS_IDS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query FileSystems[*].FileSystemId --output text|xargs -n1) + LIST_OF_EFS_IDS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query FileSystems[*].FileSystemId --output text 2>&1|xargs -n1 ) + if [[ $(echo "$LIST_OF_EFS_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe file systems" "$regx" + continue + fi if [[ $LIST_OF_EFS_IDS ]]; then for efsId in $LIST_OF_EFS_IDS;do EFS_POLICY_STATEMENTS=$($AWSCLI efs $PROFILE_OPT describe-file-system-policy --region $regx --file-system-id $efsId --output json --query Policy 2>&1) diff --git a/checks/check_extra7145 b/checks/check_extra7145 index 8ef77601..c62b7c61 100644 --- a/checks/check_extra7145 +++ b/checks/check_extra7145 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7145='IAM' extra7145(){ # "Check if lambda functions have policies which allow access to every aws account (Not Scored) (Not part of CIS benchmark)" for regx in $REGIONS; do - LIST_OF_LAMBDA_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + LIST_OF_LAMBDA_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text 2>&1) + if [[ $(echo "$LIST_OF_LAMBDA_FUNCTIONS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list functions" "$regx" + continue + fi if [[ $LIST_OF_LAMBDA_FUNCTIONS ]]; then for lambdaFunction in $LIST_OF_LAMBDA_FUNCTIONS;do FUNCTION_POLICY_STATEMENTS=$($AWSCLI lambda $PROFILE_OPT get-policy --region $regx --function-name $lambdaFunction --output json --query Policy 2>&1) diff --git a/checks/check_extra7146 b/checks/check_extra7146 index 78e56683..2c4682a8 100644 --- a/checks/check_extra7146 +++ b/checks/check_extra7146 @@ -26,7 +26,11 @@ 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) + 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') diff --git a/checks/check_extra7147 b/checks/check_extra7147 index 4e8c16e3..ef9ee88b 100644 --- a/checks/check_extra7147 +++ b/checks/check_extra7147 @@ -16,7 +16,7 @@ CHECK_SCORED_extra7147="NOT_SCORED" CHECK_CIS_LEVEL_extra7147="EXTRA" CHECK_SEVERITY_extra7147="Critical" CHECK_ASFF_RESOURCE_TYPE_extra7147="AwsGlacierVault" -CHECK_ALTERNATE_check7147="extra7142" +CHECK_ALTERNATE_check7147="extra7147" CHECK_SERVICENAME_extra7147="glacier" CHECK_RISK_extra7147='Vaults accessible to everyone could expose sensitive data to bad actors' CHECK_REMEDIATION_extra7147='Ensure vault policy does not have principle as *' @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7147='Data Protection' extra7147(){ for regx in $REGIONS; do - LIST_OF_VAULTS=$($AWSCLI glacier list-vaults $PROFILE_OPT --region $regx --account-id $ACCOUNT_NUM --query VaultList[*].VaultName --output text|xargs -n1) + LIST_OF_VAULTS=$($AWSCLI glacier list-vaults $PROFILE_OPT --region $regx --account-id $ACCOUNT_NUM --query VaultList[*].VaultName --output text 2>&1|xargs -n1) + if [[ $(echo "$LIST_OF_VAULTS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list vaults" "$regx" + continue + fi if [[ $LIST_OF_VAULTS ]]; then for vault in $LIST_OF_VAULTS;do VAULT_POLICY_STATEMENTS=$($AWSCLI glacier $PROFILE_OPT get-vault-access-policy --region $regx --account-id $ACCOUNT_NUM --vault-name $vault --output json --query policy.Policy 2>&1) diff --git a/checks/check_extra7148 b/checks/check_extra7148 index c69805b5..4f035a88 100644 --- a/checks/check_extra7148 +++ b/checks/check_extra7148 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7148='Data Protection' extra7148() { for regx in $REGIONS; do - LIST_OF_EFS_SYSTEMS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query 'FileSystems[*].FileSystemId' --output text) + LIST_OF_EFS_SYSTEMS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query 'FileSystems[*].FileSystemId' --output text 2>&1) + if [[ $(echo "$LIST_OF_EFS_SYSTEMS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe file systems" "$regx" + continue + fi if [[ $LIST_OF_EFS_SYSTEMS ]]; then for filesystem in $LIST_OF_EFS_SYSTEMS; do # if retention is 0 then is disabled diff --git a/checks/check_extra7149 b/checks/check_extra7149 index 259947d8..2fd07c6c 100644 --- a/checks/check_extra7149 +++ b/checks/check_extra7149 @@ -26,12 +26,16 @@ CHECK_CAF_EPIC_extra7149='Data Protection' extra7149() { # "Check if Redshift cluster has audit logging enabled " for regx in $REGIONS; do - LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text) + LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text 2>&1) + if [[ $(echo "$LIST_OF_REDSHIFT_CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe clusters" "$regx" + continue + fi if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then for redshiftcluster in $LIST_OF_REDSHIFT_CLUSTERS; do REDSHIFT_SNAPSHOT_ENABLED=$($AWSCLI redshift describe-cluster-snapshots $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --snapshot-type automated) if [[ $REDSHIFT_SNAPSHOT_ENABLED ]]; then - textPass "$regx: Redshift cluster $redshiftcluster has automated snapshots $REDSHIFT_SNAPSHOT_ENABLED" "$regx" "$redshiftcluster" + textPass "$regx: Redshift cluster $redshiftcluster has automated snapshots." "$regx" "$redshiftcluster" else textFail "$regx: Redshift cluster $redshiftcluster has automated snapshots disabled!" "$regx" "$redshiftcluster" fi diff --git a/checks/check_extra715 b/checks/check_extra715 index b5ccdb0e..20d03ac7 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra715='Logging and Monitoring' extra715(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do SEARCH_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.SEARCH_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) diff --git a/checks/check_extra7150 b/checks/check_extra7150 index 673a3da8..c9f945a6 100644 --- a/checks/check_extra7150 +++ b/checks/check_extra7150 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra7150='Data Protection' extra7150(){ # "Check if Elastic Load Balancers have delete protection enabled." for regx in $REGIONS; do - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1|xargs -n1 ) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBSV2 ]]; then for elb in $LIST_OF_ELBSV2; do CHECK_DELETION_PROTECTION_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elb --query Attributes[*] --output text|grep "deletion_protection.enabled"|grep true ) diff --git a/checks/check_extra7151 b/checks/check_extra7151 index a17a3673..bb95ce1a 100644 --- a/checks/check_extra7151 +++ b/checks/check_extra7151 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra7151='Data Protection' extra7151(){ # "Check if DynamoDB tables point-in-time recovery (PITR) is enabled" for regx in $REGIONS; do - LIST_OF_DYNAMODB_TABLES=$($AWSCLI dynamodb list-tables $PROFILE_OPT --region $regx --query 'TableNames[*]' --output text) + LIST_OF_DYNAMODB_TABLES=$($AWSCLI dynamodb list-tables $PROFILE_OPT --region $regx --query 'TableNames[*]' --output text 2>&1) + if [[ $(echo "$LIST_OF_DYNAMODB_TABLES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list tables" "$regx" + continue + fi if [[ $LIST_OF_DYNAMODB_TABLES ]]; then for dynamodb_table in $LIST_OF_DYNAMODB_TABLES; do POINT_IN_TIME_RECOVERY_ENABLED=$($AWSCLI dynamodb describe-continuous-backups $PROFILE_OPT --region $regx --table-name $dynamodb_table | jq '.[].PointInTimeRecoveryDescription | select(.PointInTimeRecoveryStatus=="ENABLED") | .PointInTimeRecoveryStatus') diff --git a/checks/check_extra7152 b/checks/check_extra7152 index e205de31..136a332e 100644 --- a/checks/check_extra7152 +++ b/checks/check_extra7152 @@ -23,31 +23,32 @@ # --tech-privacy CHECK_ID_extra7152="7.152" -CHECK_TITLE_extra7152="[extra7152] Enable Privacy Protection for for a Route53 Domain" +CHECK_TITLE_extra7152="[extra7152] Enable Privacy Protection for for a Route53 Domain (us-east-1 only)" CHECK_SCORED_extra7152="NOT_SCORED" CHECK_CIS_LEVEL_extra7152="EXTRA" CHECK_SEVERITY_extra7152="Medium" CHECK_ASFF_RESOURCE_TYPE_extra7152="AwsRoute53Domain" CHECK_ALTERNATE_check7152="extra7152" CHECK_SERVICENAME_extra7152="route53" -CHECK_RISK_extra7152='Without privacy protection enabled, ones personal information is published to the public WHOIS database' +CHECK_RISK_extra7152='Without privacy protection enabled; ones personal information is published to the public WHOIS database' CHECK_REMEDIATION_extra7152='Ensure default Privacy is enabled' CHECK_DOC_extra7152='https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-privacy-protection.html' CHECK_CAF_EPIC_extra7152='Data Protection' extra7152(){ - echo "Route53 is a global service, looking for domains in US-EAST-1" + # Route53 is a global service, looking for domains in US-EAST-1 + # this is also valid for GovCloud https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/setting-up-route53.html DOMAIN_NAMES=$($AWSCLI route53domains list-domains $PROFILE_OPT --region us-east-1 --query 'Domains[*].DomainName' --output text ) if [[ $DOMAIN_NAMES ]];then for domain_name in $DOMAIN_NAMES;do DOMAIN_DETAIL=$($AWSCLI route53domains get-domain-detail $PROFILE_OPT --region us-east-1 --query 'AdminPrivacy' --domain-name $domain_name) if [[ $DOMAIN_DETAIL == false ]]; then - textFail "$regx: Contact information public for: $domain_name" "$regx" "$domain_name" + textFail "us-east-1: Contact information public for: $domain_name" "us-east-1" "$domain_name" else - textPass "$regx: All contact information is private for: $domain_name" "$regx" "$domain_name" + textPass "us-east-1: All contact information is private for: $domain_name" "us-east-1" "$domain_name" fi done else - textPass "$regx: No Domain Names found" "$regx" + textInfo "us-east-1: No Domain Names found" "us-east-1" fi } diff --git a/checks/check_extra7153 b/checks/check_extra7153 index eee485c5..e7f31b2b 100644 --- a/checks/check_extra7153 +++ b/checks/check_extra7153 @@ -20,32 +20,33 @@ CHECK_ID_extra7153="7.153" -CHECK_TITLE_extra7153="[extra7153] Enable Transfer Lock for a Route53 Domain" +CHECK_TITLE_extra7153="[extra7153] Enable Transfer Lock for a Route53 Domain (us-east-1 only)" CHECK_SCORED_extra7153="NOT_SCORED" CHECK_CIS_LEVEL_extra7153="EXTRA" CHECK_SEVERITY_extra7153="Medium" CHECK_ASFF_RESOURCE_TYPE_extra7153="AwsRoute53Domain" CHECK_ALTERNATE_check7153="extra7153" CHECK_SERVICENAME_extra7153="route53" -CHECK_RISK_extra7153='Without transfer lock enabled, a domain name could be incorrectly moved to a new registrar' +CHECK_RISK_extra7153='Without transfer lock enabled; a domain name could be incorrectly moved to a new registrar' CHECK_REMEDIATION_extra7153='Ensure transfer lock is enabled' CHECK_DOC_extra7153='https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-lock.html' CHECK_CAF_EPIC_extra7153='Data Protection' extra7153(){ # Route53 is a global service, looking for domains in US-EAST-1 + # this is also valid for GovCloud https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/setting-up-route53.html DOMAIN_NAMES=$($AWSCLI route53domains list-domains $PROFILE_OPT --region us-east-1 --query 'Domains[*].DomainName' --output text ) if [[ $DOMAIN_NAMES ]];then for domain_name in $DOMAIN_NAMES;do DOMAIN_DETAIL=$($AWSCLI route53domains get-domain-detail $PROFILE_OPT --region us-east-1 --query 'StatusList' --domain-name $domain_name) HAS_TRANSFER_LOCK=$( grep -o 'clientTransferProhibited' <<< $DOMAIN_DETAIL) if [[ $HAS_TRANSFER_LOCK ]]; then - textPass "$regx: clientTransferProhibited found for: $domain_name" "$regx" "$domain_name" + textPass "us-east-1: clientTransferProhibited found for: $domain_name" "us-east-1" "$domain_name" else - textFail "$regx: clientTransferProhibited not found for: $domain_name" "$regx" "$domain_name" + textFail "us-east-1: clientTransferProhibited not found for: $domain_name" "us-east-1" "$domain_name" fi done else - textPass "$regx: No Domain Names found" "$regx" + textInfo "us-east-1: No Domain Names found" "us-east-1" fi } diff --git a/checks/check_extra7154 b/checks/check_extra7154 index 8ea2efe6..7d4dcc42 100644 --- a/checks/check_extra7154 +++ b/checks/check_extra7154 @@ -34,7 +34,11 @@ CHECK_CAF_EPIC_extra7154='Infrastructure Protection' extra7154() { for regx in $REGIONS; do - CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --output json) + CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --output json 2>&1) + if [[ $(echo "$CFN_STACKS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe stacks" "$regx" + continue + fi LIST_OF_CFN_STACKS=$(echo $CFN_STACKS | jq -r '.Stacks[].StackName') if [[ $LIST_OF_CFN_STACKS ]];then for stack in $LIST_OF_CFN_STACKS; do diff --git a/checks/check_extra7155 b/checks/check_extra7155 index 7c663886..e593a805 100644 --- a/checks/check_extra7155 +++ b/checks/check_extra7155 @@ -33,7 +33,11 @@ CHECK_CAF_EPIC_extra7155='Data Protection' extra7155() { for regx in $REGIONS; do - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text 2>&1) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBSV2 ]];then for alb in $LIST_OF_ELBSV2;do CHECK_DESYNC_MITIGATION_MODE=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $alb --query 'Attributes[8]' --output json | jq -r '.Value') diff --git a/checks/check_extra7156 b/checks/check_extra7156 index 529c0616..7c8de499 100644 --- a/checks/check_extra7156 +++ b/checks/check_extra7156 @@ -28,7 +28,11 @@ extra7156(){ # "Check if API Gateway V2 has Access Logging enabled " for regx in $REGIONS; do - LIST_OF_API_GW=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query Items[*].ApiId --output text) + LIST_OF_API_GW=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query Items[*].ApiId --output text 2>&1) + if [[ $(echo "$LIST_OF_API_GW" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get APIs" "$regx" + continue + fi if [[ $LIST_OF_API_GW ]];then for apigwid in $LIST_OF_API_GW;do API_GW_NAME=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query "Items[?ApiId==\`$apigwid\`].Name" --output text) @@ -37,9 +41,9 @@ extra7156(){ for stagename in $CHECK_STAGES_NAME;do CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigatewayv2 get-stages $PROFILE_OPT --region $regx --api-id $apigwid --query "Items[?StageName == \`$stagename\` ].AccessLogSettings.DestinationArn" --output text) if [[ $CHECK_STAGE_METHOD_LOGGING ]];then - textPass "$regx: API Gateway V2 $API_GW_NAME ID: $apigwid, stage: $stagename, has access logging enabled to $CHECK_STAGE_METHOD_LOGGING" "$regx" "$API_GW_NAME" + textPass "$regx: API Gateway V2 $API_GW_NAME ID: $apigwid with stage: $stagename has access logging enabled to $CHECK_STAGE_METHOD_LOGGING" "$regx" "$API_GW_NAME" else - textFail "$regx: API Gateway V2 $API_GW_NAME ID: $apigwid, stage: $stagename, has access logging disabled" "$regx" "$API_GW_NAME" + textFail "$regx: API Gateway V2 $API_GW_NAME ID: $apigwid with stage: $stagename has access logging disabled" "$regx" "$API_GW_NAME" fi done else diff --git a/checks/check_extra7157 b/checks/check_extra7157 index ec62f4a8..755435c5 100644 --- a/checks/check_extra7157 +++ b/checks/check_extra7157 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7157='IAM' extra7157(){ for regx in $REGIONS; do - LIST_OF_API_GW=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query "Items[*].ApiId" --output text) + LIST_OF_API_GW=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query "Items[*].ApiId" --output text 2>&1) + if [[ $(echo "$LIST_OF_API_GW" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get APIs" "$regx" + continue + fi if [[ $LIST_OF_API_GW ]];then for api in $LIST_OF_API_GW; do API_GW_NAME=$($AWSCLI apigatewayv2 get-apis $PROFILE_OPT --region $regx --query "Items[?ApiId==\`$api\`].Name" --output text) diff --git a/checks/check_extra7158 b/checks/check_extra7158 index 3aaf74ec..ee1bad9f 100644 --- a/checks/check_extra7158 +++ b/checks/check_extra7158 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7158='Data Protection' extra7158(){ for regx in $REGIONS; do - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers --query 'LoadBalancers[*].LoadBalancerArn' $PROFILE_OPT --region $regx --output text) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers --query 'LoadBalancers[*].LoadBalancerArn' $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBSV2 ]]; then for elb in $LIST_OF_ELBSV2; do LIST_OF_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elb --query 'Listeners[*]' --output text) diff --git a/checks/check_extra7159 b/checks/check_extra7159 index 58437519..ddbe5452 100644 --- a/checks/check_extra7159 +++ b/checks/check_extra7159 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra7159='Data Protection' extra7159(){ for regx in $REGIONS; do - LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers --query 'LoadBalancerDescriptions[*].LoadBalancerName' $PROFILE_OPT --region $regx --output text) + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers --query 'LoadBalancerDescriptions[*].LoadBalancerName' $PROFILE_OPT --region $regx --output text 2>&1) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBS ]]; then for elb in $LIST_OF_ELBS; do LIST_OF_LISTENERS=$($AWSCLI elb describe-load-balancers --load-balancer-name $elb --query 'LoadBalancerDescriptions[*].ListenerDescriptions' $PROFILE_OPT --region $regx --output text) diff --git a/checks/check_extra716 b/checks/check_extra716 index 87980aea..0bac7f7f 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra716='Infrastructure Security' extra716(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX) diff --git a/checks/check_extra7160 b/checks/check_extra7160 new file mode 100644 index 00000000..066fa66b --- /dev/null +++ b/checks/check_extra7160 @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2021) 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_extra7160="7.160" +CHECK_TITLE_extra7160="[extra7160] Check if Redshift has automatic upgrades enabled" +CHECK_SCORED_extra7160="NOT_SCORED" +CHECK_CIS_LEVEL_extra7160="EXTRA" +CHECK_SEVERITY_extra7160="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7160="AwsRedshift" +CHECK_ALTERNATE_check7160="extra7160" +CHECK_SERVICENAME_extra7160="redshift" +CHECK_RISK_extra7160='Without automatic version upgrade enabled; a critical Redshift Cluster version can become severly out of date.' +CHECK_REMEDIATION_extra7160='Enabled AutomaticVersionUpgrade on Redshift Cluster' +CHECK_DOC_extra7160='https://docs.aws.amazon.com/redshift/latest/mgmt/managing-cluster-operations.html' +CHECK_CAF_EPIC_extra7160='Infrastructure Security' + +extra7160(){ + for regx in $REGIONS; do + LIST_OF_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --query 'Clusters[*].ClusterIdentifier' --region $regx --output text 2>&1) + if [[ $(echo "$LIST_OF_CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe clusters" "$regx" + continue + fi + if [[ $LIST_OF_CLUSTERS ]]; then + for cluster in $LIST_OF_CLUSTERS; do + AUTO_UPGRADE_ENABLED=$($AWSCLI redshift describe-clusters $PROFILE_OPT --cluster-identifier $cluster --query 'Clusters[*].AllowVersionUpgrade' --region $regx --output text) + if [[ $AUTO_UPGRADE_ENABLED == "True" ]]; then + textPass "$regx: $cluster has AllowVersionUpgrade enabled" "$regx" "$cluster" + else + textFail "$regx: $cluster has AllowVersionUpgrade disabled" "$regx" "$cluster" + fi + done + else + textInfo "$regx: No Redshift Clusters found" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7161 b/checks/check_extra7161 new file mode 100644 index 00000000..0fbe0021 --- /dev/null +++ b/checks/check_extra7161 @@ -0,0 +1,47 @@ +#!/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_extra7161="7.161" +CHECK_TITLE_extra7161="[extra7161] Check if EFS have protects sensative data with encryption at rest" +CHECK_SCORED_extra7161="NOT_SCORED" +CHECK_CIS_LEVEL_extra7161="EXTRA" +CHECK_SEVERITY_extra7161="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7161="AwsEfsFileSystem" +CHECK_ALTERNATE_check7161="extra7161" +CHECK_SERVICENAME_extra7161="efs" +CHECK_RISK_extra7161='EFS should be encrypted at rest to prevent exposure of sensitive data to bad actors' +CHECK_REMEDIATION_extra7161='Ensure that encryption at rest is enabled for EFS file systems. Encryption at rest can only be enabled during the file system creation.' +CHECK_DOC_extra7161='https://docs.aws.amazon.com/efs/latest/ug/encryption-at-rest.html' +CHECK_CAF_EPIC_extra7161='Data Protection' + +extra7161(){ + # "Check if EFS has encryption at rest enabled (Not Scored) (Proposed requirement for 1.5 CIS benchmark)" + for regx in $REGIONS; do + LIST_OF_EFS_IDS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query 'FileSystems[*].FileSystemId' --output text 2>&1| xargs -n1 ) + if [[ $(echo "$LIST_OF_EFS_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe file systems" "$regx" + continue + fi + if [[ $LIST_OF_EFS_IDS ]]; then + for efsId in $LIST_OF_EFS_IDS;do + EFS_ENCRYPTION_CHECK=$($AWSCLI efs $PROFILE_OPT describe-file-systems --region $regx --file-system-id $efsId --output json --query 'FileSystems[*].Encrypted' --output text) + if [[ $EFS_ENCRYPTION_CHECK == "True" ]]; then + textPass "$regx: EFS $efsId has has encryption at rest enabled" "$regx" "$efsId" + else + textFail "$regx: EFS: $efsId does not have encryption at rest enabled" "$regx" "$efsId" + fi + done + else + textInfo "$regx: No EFS found" "$regx" + fi + done +} diff --git a/checks/check_extra7162 b/checks/check_extra7162 new file mode 100644 index 00000000..b0d17eac --- /dev/null +++ b/checks/check_extra7162 @@ -0,0 +1,54 @@ +#!/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_extra7162="7.162" +CHECK_TITLE_extra7162="[extra7162] Check if CloudWatch Log Groups have a retention policy of 365 days" +CHECK_SCORED_extra7162="NOT_SCORED" +CHECK_CIS_LEVEL_extra7162="EXTRA" +CHECK_SEVERITY_extra7162="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7162="AwsLogsLogGroup" +CHECK_ALTERNATE_check7162="extra7162" +CHECK_SERVICENAME_extra7162="cloudwatch" +CHECK_RISK_extra7162='If log groups have a low retention policy of less than 365 days; crucial logs and data can be lost' +CHECK_REMEDIATION_extra7162='Add Log Retention policy of 365 days to log groups. This will persist logs and traces for a long time.' +CHECK_DOC_extra7162='https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Logs.html' +CHECK_CAF_EPIC_extra7162='Data Retention' + +extra7162() { + # "Check if CloudWatch Log Groups have a retention policy of 365 days" + declare -i LOG_GROUP_RETENTION_PERIOD_DAYS=365 + for regx in $REGIONS; do + LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays=="${LOG_GROUP_RETENTION_PERIOD_DAYS}"].[logGroupName]' --output text 2>&1) + if [[ $(echo "$LIST_OF_365_RETENTION_LOG_GROUPS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe log groups" "$regx" + continue + fi + if [[ $LIST_OF_365_RETENTION_LOG_GROUPS ]]; then + for log in $LIST_OF_365_RETENTION_LOG_GROUPS; do + textPass "$regx: $log Log Group has 365 days retention period!" "$regx" "$log" + done + fi + LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!="${LOG_GROUP_RETENTION_PERIOD_DAYS}"].[logGroupName]' --output text) + if [[ $LIST_OF_NON_365_RETENTION_LOG_GROUPS ]]; then + for log in $LIST_OF_NON_365_RETENTION_LOG_GROUPS; do + textFail "$regx: $log Log Group does not have 365 days retention period!" "$regx" "$log" + done + fi + REGION_NO_LOG_GROUP=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --output text) + if [[ $REGION_NO_LOG_GROUP ]]; then + : + else + textInfo "$regx does not have a Log Group!" "$regx" + + fi + done +} diff --git a/checks/check_extra7163 b/checks/check_extra7163 new file mode 100644 index 00000000..6d5b45d8 --- /dev/null +++ b/checks/check_extra7163 @@ -0,0 +1,61 @@ +#!/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. + +# Remediation: +# +# https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/rotate-secret.html +# +# rotate-secret +# --secret-id +# [--client-request-token ] +# [--rotation-lambda-arn ] +# [--rotation-rules ] +# [--cli-input-json ] +# [--generate-cli-skeleton ] + + +CHECK_ID_extra7163="7.163" +CHECK_TITLE_extra7163="[extra7163] Check if Secrets Manager key rotation is enabled" +CHECK_SCORED_extra7163="NOT_SCORED" +CHECK_CIS_LEVEL_extra7163="EXTRA" +CHECK_SEVERITY_extra7163="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7163="AwsSecretsManagerSecret" +CHECK_ALTERNATE_extra7163="extra7163" +CHECK_SERVICENAME_extra7163="secretsmanager" +CHECK_RISK_extra7163="Rotating secrets minimizes exposure to attacks using stolen keys." +CHECK_REMEDITATION_extra7163="Enable key rotation on Secrets Manager key." +CHECK_DOC_extra7163="https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html" +CHECK_CAF_EPIC_extra7163="Data Protection" + +extra7163(){ + # "Check if Secrets Manager key rotation is enabled" + for regx in $REGIONS; do + LIST_OF_SECRETS=$($AWSCLI secretsmanager list-secrets $PROFILE_OPT --region $regx --query 'SecretList[*].Name' --output text 2>&1) + if [[ $(echo "$LIST_OF_SECRETS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list secrets" "$regx" + continue + fi + if [[ $LIST_OF_SECRETS ]]; then + for secret in $LIST_OF_SECRETS; do + KEY_ROTATION_ENABLED=$($AWSCLI secretsmanager describe-secret $PROFILE_OPT --region $regx --secret-id $secret --output json | jq '.RotationEnabled') + if [[ $KEY_ROTATION_ENABLED == true ]]; then + textPass "$regx: $secret has key rotation enabled." "$regx" "$secret" + else + textFail "$regx: $secret does not have key rotation enabled." "$regx" "$secret" + fi + done + else + textPass "$regx: No Secrets Manager secrets found." "$regx" + fi + done +} diff --git a/checks/check_extra7164 b/checks/check_extra7164 new file mode 100644 index 00000000..9c9a8198 --- /dev/null +++ b/checks/check_extra7164 @@ -0,0 +1,61 @@ +#!/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. + +# Remediation: +# +# https://docs.aws.amazon.com/cli/latest/reference/logs/associate-kms-key.html +# associate-kms-key +# --log-group-name +# --kms-key-id +# [--cli-input-json ] +# [--generate-cli-skeleton ] + +CHECK_ID_extra7164="7.164" +CHECK_TITLE_extra7164="[extra7164] Check if CloudWatch log groups are protected by AWS KMS " +CHECK_SCORED_extra7164="NOT_SCORED" +CHECK_CIS_LEVEL_extra7164="EXTRA" +CHECK_SEVERITY_extra7164="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7164="Logs" +CHECK_ALTERNATE_extra7164="extra7164" +CHECK_SERVICENAME_extra7164="logs" +CHECK_RISK_extra7164="Using customer managed KMS to encrypt CloudWatch log group provide additional confidentiality and control over the log data" +CHECK_REMEDITATION_extra7164="Associate KMS Key with Cloudwatch log group." +CHECK_DOC_extra7164="https://docs.aws.amazon.com/cli/latest/reference/logs/associate-kms-key.html" +CHECK_CAF_EPIC_extra7164="Data Protection" + +extra7164(){ + # "Check if Cloudwatch log groups are associated with AWS KMS" + for regx in $REGIONS; do + LIST_OF_LOGGROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --output json 2>&1 ) + if [[ $(echo "$LIST_OF_LOGGROUPS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe log groups" "$regx" + continue + fi + if [[ $LIST_OF_LOGGROUPS ]]; then + LIST_OF_LOGGROUPS_WITHOUT_KMS=$(echo "${LIST_OF_LOGGROUPS}" | jq '.logGroups[]' | jq '. | select( has("kmsKeyId") == false )' | jq -r '.logGroupName') + LIST_OF_LOGGROUPS_WITH_KMS=$(echo "${LIST_OF_LOGGROUPS}" | jq '.logGroups[]' | jq '. | select( has("kmsKeyId") == true )' | jq -r '.logGroupName') + if [[ $LIST_OF_LOGGROUPS_WITHOUT_KMS ]]; then + for loggroup in $LIST_OF_LOGGROUPS_WITHOUT_KMS; do + textFail "$regx: ${loggroup} does not have AWS KMS keys associated." "$regx" "${loggroup}" + done + fi + if [[ $LIST_OF_LOGGROUPS_WITH_KMS ]]; then + for loggroup in $LIST_OF_LOGGROUPS_WITH_KMS; do + textPass "$regx: ${loggroup} does have AWS KMS keys associated." "$regx" "${loggroup}" + done + fi + else + textPass "$regx: No Cloudwatch log groups found." "$regx" + fi + done +} diff --git a/checks/check_extra7165 b/checks/check_extra7165 new file mode 100644 index 00000000..95f990a5 --- /dev/null +++ b/checks/check_extra7165 @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Remediation +# +# https://docs.aws.amazon.com/cli/latest/reference/dax/create-cluster.html +# +# create-cluster +# --cluster-name +# --node-type +# --replication-factor +# --iam-role-arn +# --sse-specification Enabled=true + + +CHECK_ID_extra7165="7.165" +CHECK_TITLE_extra7165="[extra7165] Check if DynamoDB: DAX Clusters are encrypted at rest" +CHECK_SCORED_extra7165="NOT_SCORED" +CHECK_CIS_LEVEL_extra7165="EXTRA" +CHECK_SEVERITY_extra7165="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7165="AwsDaxCluster" +CHECK_ALTERNATE_check7165="extra7165" +CHECK_SERVICENAME_extra7165="dynamodb" +CHECK_RISK_extra7165="Encryption at rest provides an additional layer of data protection by securing your data from unauthorized access to the underlying storage." +CHECK_REMEDIATION_extra7165="Re-create the cluster to enable encryption at rest if it was not enabled at creation." +CHECK_DOC_extra7165="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAXEncryptionAtRest.html" +CHECK_CAF_EPIC_extra7165="Data Protection" + +extra7165(){ + # "Check if DynamoDB: DAX Clusters are encrypted at rest" + for regx in $REGIONS; do + LIST_OF_DAX_CLUSTERS=$($AWSCLI dax describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*]' --output json 2>&1) + if [[ $(echo "$LIST_OF_DAX_CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe clusters" "$regx" + continue + fi + if [[ $(echo "$LIST_OF_DAX_CLUSTERS" | grep -E 'Could not connect') ]]; then + textInfo "$regx: Service not available in this region" "$regx" + continue + fi + if [[ $LIST_OF_DAX_CLUSTERS && $LIST_OF_DAX_CLUSTERS != '[]' ]]; then + LIST_OF_CLUSTERS_WITH_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="ENABLED") | {ClusterName}' | jq -r '.ClusterName') + LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="DISABLED") | {ClusterName}' | jq -r '.ClusterName') + if [[ $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION; do + textFail "$regx: ${cluster} does not have encryption at rest enabled." "$regx" "${cluster}" + done + fi + if [[ $LIST_OF_CLUSTERS_WITH_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITH_ENCRYPTION; do + textPass "$regx: ${cluster} has encryption at rest enabled." "$regx" "${cluster}" + done + fi + else + textInfo "$regx: No DynamoDB: DAX Clusters found." "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7166 b/checks/check_extra7166 new file mode 100644 index 00000000..4a8430f5 --- /dev/null +++ b/checks/check_extra7166 @@ -0,0 +1,50 @@ +#!/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_extra7166="7.166" +CHECK_TITLE_extra7166="[extra7166] Check if Elastic IP addresses with associations are protected by AWS Shield Advanced" +CHECK_SCORED_extra7166="NOT_SCORED" +CHECK_CIS_LEVEL_extra7166="EXTRA" +CHECK_SEVERITY_extra7166="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7166="AwsEc2Eip" +CHECK_ALTERNATE_check7166="extra7166" +CHECK_SERVICENAME_extra7166="shield" +CHECK_RISK_extra7166='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7166='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7166='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7166='Infrastructure security' + +extra7166() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) + PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) + ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) + for regx in $REGIONS; do + LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS=$($AWSCLI ec2 describe-addresses $PROFILE_OPT --region $regx --query 'Addresses[?AssociationId].AllocationId' --output text) + if [[ $LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS ]]; then + for elastic_ip in $LIST_OF_ELASTIC_IPS_WITH_ASSOCIATIONS; do + EIP_ARN="arn:${PARTITION}:ec2:${regx}:${ACCOUNT_ID}:eip-allocation/${elastic_ip}" + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $EIP_ARN >/dev/null 2>&1; then + textPass "$regx: EIP $elastic_ip is protected by AWS Shield Advanced" "$regx" "$elastic_ip" + else + textFail "$regx: EIP $elastic_ip is not protected by AWS Shield Advanced" "$regx" "$elastic_ip" + fi + done + else + textInfo "$regx: no elastic IP addresses with assocations found" "$regx" + fi + done + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra7167 b/checks/check_extra7167 new file mode 100644 index 00000000..18ce6209 --- /dev/null +++ b/checks/check_extra7167 @@ -0,0 +1,46 @@ +#!/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_extra7167="7.167" +CHECK_TITLE_extra7167="[extra7167] Check if Cloudfront distributions are protected by AWS Shield Advanced" +CHECK_SCORED_extra7167="NOT_SCORED" +CHECK_CIS_LEVEL_extra7167="EXTRA" +CHECK_SEVERITY_extra7167="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7167="AwsCloudFrontDistribution" +CHECK_ALTERNATE_check7167="extra7167" +CHECK_SERVICENAME_extra7167="shield" +CHECK_RISK_extra7167='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7167='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7167='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7167='Infrastructure security' + +extra7167() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + LIST_OF_CLOUDFRONT_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --query 'DistributionList.Items[*].[Id,ARN]' --output text) + if [[ $LIST_OF_CLOUDFRONT_DISTRIBUTIONS ]]; then + while read -r distribution; do + DISTRIBUTION_ID=$(echo $distribution | awk '{ print $1; }') + DISTRIBUTION_ARN=$(echo $distribution | awk '{ print $2; }') + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $DISTRIBUTION_ARN >/dev/null 2>&1; then + textPass "$REGION: Cloudfront distribution $DISTRIBUTION_ID is protected by AWS Shield Advanced" "$REGION" "$DISTRIBUTION_ID" + else + textFail "$REGION: Cloudfront distribution $DISTRIBUTION_ID is not protected by AWS Shield Advanced" "$REGION" "$DISTRIBUTION_ID" + fi + done <<<"$LIST_OF_CLOUDFRONT_DISTRIBUTIONS" + else + textInfo "$REGION: no Cloudfront distributions found" "$REGION" + fi + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra7168 b/checks/check_extra7168 new file mode 100644 index 00000000..e2f2514d --- /dev/null +++ b/checks/check_extra7168 @@ -0,0 +1,49 @@ +#!/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_extra7168="7.168" +CHECK_TITLE_extra7168="[extra7168] Check if Route53 hosted zones are protected by AWS Shield Advanced" +CHECK_SCORED_extra7168="NOT_SCORED" +CHECK_CIS_LEVEL_extra7168="EXTRA" +CHECK_SEVERITY_extra7168="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7168="AwsRoute53Domain" +CHECK_ALTERNATE_check7168="extra7168" +CHECK_SERVICENAME_extra7168="shield" +CHECK_RISK_extra7168='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7168='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7168='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7168='Infrastructure security' + +extra7168() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) + PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) + LIST_OF_ROUTE53_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT --query 'HostedZones[*].[Id,Name]' --output text) + if [[ $LIST_OF_ROUTE53_HOSTED_ZONES ]]; then + while read -r hosted_zone; do + HOSTED_ZONE_ID=$(echo $hosted_zone | awk '{ print $1; }') + HOSTED_ZONE_NAME=$(echo $hosted_zone | awk '{ print $2; }') + HOSTED_ZONE_ARN="arn:${PARTITION}:route53:::${HOSTED_ZONE_ID:1}" + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $HOSTED_ZONE_ARN >/dev/null 2>&1; then + textPass "$REGION: Route53 Hosted Zone $HOSTED_ZONE_NAME is protected by AWS Shield Advanced" "$REGION" "$HOSTED_ZONE_NAME" + else + textFail "$REGION: Route53 Hosted Zone $HOSTED_ZONE_NAME is not protected by AWS Shield Advanced" "$REGION" "$HOSTED_ZONE_NAME" + fi + done <<<"$LIST_OF_ROUTE53_HOSTED_ZONES" + else + textInfo "$REGION: no Route53 hosted zones found" "$REGION" + fi + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra7169 b/checks/check_extra7169 new file mode 100644 index 00000000..573c0415 --- /dev/null +++ b/checks/check_extra7169 @@ -0,0 +1,46 @@ +#!/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_extra7169="7.169" +CHECK_TITLE_extra7169="[extra7169] Check if global accelerators are protected by AWS Shield Advanced" +CHECK_SCORED_extra7169="NOT_SCORED" +CHECK_CIS_LEVEL_extra7169="EXTRA" +CHECK_SEVERITY_extra7169="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7169="AwsGlobalAccelerator" +CHECK_ALTERNATE_check7169="extra7169" +CHECK_SERVICENAME_extra7169="shield" +CHECK_RISK_extra7169='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7169='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7169='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7169='Infrastructure security' + +extra7169() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + LIST_OF_GLOBAL_ACCELERATORS=$($AWSCLI globalaccelerator list-accelerators --region us-west-2 $PROFILE_OPT --query 'Accelerators[?Enabled].[Name,AcceleratorArn]' --output text) + if [[ $LIST_OF_GLOBAL_ACCELERATORS ]]; then + while read -r accelerator; do + ACCELERATOR_NAME=$(echo $accelerator | awk '{ print $1; }') + ACCELERATOR_ARN=$(echo $accelerator | awk '{ print $2; }') + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $ACCELERATOR_ARN >/dev/null 2>&1; then + textPass "$REGION: Global Accelerator $ACCELERATOR_NAME is protected by AWS Shield Advanced" "$REGION" "$ACCELERATOR_NAME" + else + textFail "$REGION: Global Accelerator $ACCELERATOR_NAME is not protected by AWS Shield Advanced" "$REGION" "$ACCELERATOR_NAME" + fi + done <<<"$LIST_OF_GLOBAL_ACCELERATORS" + else + textInfo "$REGION: no global accelerators found" "$REGION" + fi + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra717 b/checks/check_extra717 index aa42a36e..4be331cd 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -26,12 +26,20 @@ CHECK_CAF_EPIC_extra717='Logging and Monitoring' extra717(){ # "Check if Elastic Load Balancers have logging enabled " for regx in $REGIONS; do - LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1 |xargs -n1) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list load balancers v1" "$regx" + continue + fi + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1 |xargs -n1) + if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list load balancers v2" "$regx" + continue + fi if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then if [[ $LIST_OF_ELBS ]]; then for elb in $LIST_OF_ELBS; do - CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled'|grep "^true") + CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled' |grep "^true") if [[ $CHECK_ELBS_LOG_ENABLED ]]; then textPass "$regx: $elb has access logs to S3 configured" "$regx" "$elb" else @@ -41,7 +49,7 @@ extra717(){ fi if [[ $LIST_OF_ELBSV2 ]]; then for elbarn in $LIST_OF_ELBSV2; do - CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text|grep "^access_logs.s3.enabled"|cut -f2|grep true) + CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text |grep "^access_logs.s3.enabled"|cut -f2|grep true) ELBV2_NAME=$(echo $elbarn|cut -d\/ -f3) if [[ $CHECK_ELBSV2_LOG_ENABLED ]]; then textPass "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" "$elb" diff --git a/checks/check_extra7170 b/checks/check_extra7170 new file mode 100644 index 00000000..f8675a5c --- /dev/null +++ b/checks/check_extra7170 @@ -0,0 +1,48 @@ +#!/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_extra7170="7.170" +CHECK_TITLE_extra7170="[extra7170] Check if internet-facing application load balancers are protected by AWS Shield Advanced" +CHECK_SCORED_extra7170="NOT_SCORED" +CHECK_CIS_LEVEL_extra7170="EXTRA" +CHECK_SEVERITY_extra7170="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7170="AwsElasticLoadBalancingV2LoadBalancer" +CHECK_ALTERNATE_check7170="extra7170" +CHECK_SERVICENAME_extra7170="shield" +CHECK_RISK_extra7170='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7170='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7170='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7170='Infrastructure security' + +extra7170() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + for regx in $REGIONS; do + LIST_OF_APPLICATION_LOAD_BALANCERS=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application` && Scheme == `internet-facing`].[LoadBalancerName,LoadBalancerArn]' --output text) + if [[ $LIST_OF_APPLICATION_LOAD_BALANCERS ]]; then + while read -r alb; do + ALB_NAME=$(echo $alb | awk '{ print $1; }') + ALB_ARN=$(echo $alb | awk '{ print $2; }') + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $ALB_ARN >/dev/null 2>&1; then + textPass "$regx: ALB $ALB_NAME is protected by AWS Shield Advanced" "$regx" "$ALB_NAME" + else + textFail "$regx: ALB $ALB_NAME is not protected by AWS Shield Advanced" "$regx" "$ALB_NAME" + fi + done <<<"$LIST_OF_APPLICATION_LOAD_BALANCERS" + else + textInfo "$regx: no application load balancers found" "$regx" + fi + done + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra7171 b/checks/check_extra7171 new file mode 100644 index 00000000..61834e58 --- /dev/null +++ b/checks/check_extra7171 @@ -0,0 +1,50 @@ +#!/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_extra7171="7.171" +CHECK_TITLE_extra7171="[extra7171] Check if classic load balancers are protected by AWS Shield Advanced" +CHECK_SCORED_extra7171="NOT_SCORED" +CHECK_CIS_LEVEL_extra7171="EXTRA" +CHECK_SEVERITY_extra7171="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7171="AwsElasticLoadBalancingLoadBalancer" +CHECK_ALTERNATE_check7171="extra7171" +CHECK_SERVICENAME_extra7171="shield" +CHECK_RISK_extra7171='AWS Shield Advanced provides expanded DDoS attack protection for your resources' +CHECK_REMEDIATION_extra7171='Add as a protected resource in AWS Shield Advanced.' +CHECK_DOC_extra7171='https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html' +CHECK_CAF_EPIC_extra7171='Infrastructure security' + +extra7171() { + if [[ "$($AWSCLI $PROFILE_OPT shield get-subscription-state --output text)" == "ACTIVE" ]]; then + CALLER_IDENTITY=$($AWSCLI sts get-caller-identity $PROFILE_OPT --query Arn) + PARTITION=$(echo $CALLER_IDENTITY | cut -d: -f2) + ACCOUNT_ID=$(echo $CALLER_IDENTITY | cut -d: -f5) + for regx in $REGIONS; do + LIST_OF_CLASSIC_LOAD_BALANCERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName]' --output text |grep -v '^None$') + if [[ $LIST_OF_CLASSIC_LOAD_BALANCERS ]]; then + for elb in $LIST_OF_CLASSIC_LOAD_BALANCERS; do + ELB_ARN="arn:${PARTITION}:elasticloadbalancing:${regx}:${ACCOUNT_ID}:loadbalancer/${elb}" + if $AWSCLI $PROFILE_OPT shield describe-protection --resource-arn $ELB_ARN >/dev/null 2>&1; then + textPass "$regx: ELB $elb is protected by AWS Shield Advanced" "$regx" "$elb" + else + textFail "$regx: ELB $elb is not protected by AWS Shield Advanced" "$regx" "$elb" + fi + done + else + textInfo "$regx: no classic load balancers found" "$regx" + fi + done + else + textInfo "No AWS Shield Advanced subscription found. Skipping check." + fi +} diff --git a/checks/check_extra718 b/checks/check_extra718 index c747e1c8..775d7958 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -30,7 +30,7 @@ extra718(){ for bucket in $LIST_OF_BUCKETS;do BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text 2>&1) if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied Trying to Get Bucket Logging for $bucket" "$REGION" "$bucket" + textInfo "$REGION: Access Denied Trying to Get Bucket Logging for $bucket" "$REGION" "$bucket" continue fi if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep "^None$") ]]; then diff --git a/checks/check_extra72 b/checks/check_extra72 index 019bfb26..36ba6ed4 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -28,7 +28,11 @@ CHECK_CAF_EPIC_extra72='Data Protection' extra72(){ # "Ensure there are no EBS Snapshots set as Public " for regx in $REGIONS; do - LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) + LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS 2>&1 | grep -v None ) + if [[ $(echo "$LIST_OF_EBS_SNAPSHOTS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe snapshot" "$regx" + continue + fi for snapshot in $LIST_OF_EBS_SNAPSHOTS; do SNAPSHOT_IS_PUBLIC=$($AWSCLI ec2 describe-snapshot-attribute $PROFILE_OPT --region $regx --output text --snapshot-id $snapshot --attribute createVolumePermission --query "CreateVolumePermissions[?Group=='all']") if [[ $SNAPSHOT_IS_PUBLIC ]];then diff --git a/checks/check_extra720 b/checks/check_extra720 index 7f035229..c8af3fca 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -28,13 +28,13 @@ extra720(){ for regx in $REGIONS; do LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query 'Functions[*].FunctionName' --output text 2>&1) if [[ $(echo "$LIST_OF_FUNCTIONS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to list functions" "$regx" + textInfo "$regx: Access Denied trying to list functions" "$regx" continue fi if [[ $LIST_OF_FUNCTIONS ]]; then LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].TrailARN' --output text 2>&1) if [[ $(echo "$LIST_OF_TRAILS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied trying to describe trails" "$regx" + textInfo "$regx: Access Denied trying to describe trails" "$regx" continue fi for lambdafunction in $LIST_OF_FUNCTIONS; do diff --git a/checks/check_extra721 b/checks/check_extra721 index 7d63b0ee..4d4116ff 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra721='Logging and Monitoring' extra721(){ # "Check if Redshift cluster has audit logging enabled " for regx in $REGIONS; do - LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text) + LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text 2>&1) + if [[ $(echo "$LIST_OF_REDSHIFT_CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe clusters" "$regx" + continue + fi if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then for redshiftcluster in $LIST_OF_REDSHIFT_CLUSTERS;do REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True) diff --git a/checks/check_extra722 b/checks/check_extra722 index 3def51c4..ab992174 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra722='Logging and Monitoring' extra722(){ # "Check if API Gateway has logging enabled " for regx in $REGIONS; do - LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text) + LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text 2>&1) + if [[ $(echo "$LIST_OF_API_GW" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_API_GW ]];then for apigwid in $LIST_OF_API_GW;do API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$apigwid\`].name" --output text) diff --git a/checks/check_extra723 b/checks/check_extra723 index 94833c23..7f4aee3f 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -27,7 +27,11 @@ extra723(){ # "Check if RDS Snapshots are public " for regx in $REGIONS; do # RDS snapshots - LIST_OF_RDS_SNAPSHOTS=$($AWSCLI rds describe-db-snapshots $PROFILE_OPT --region $regx --query DBSnapshots[*].DBSnapshotIdentifier --output text) + LIST_OF_RDS_SNAPSHOTS=$($AWSCLI rds describe-db-snapshots $PROFILE_OPT --region $regx --query DBSnapshots[*].DBSnapshotIdentifier --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_SNAPSHOTS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe db snapshots" "$regx" + continue + fi if [[ $LIST_OF_RDS_SNAPSHOTS ]]; then for rdssnapshot in $LIST_OF_RDS_SNAPSHOTS;do SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-snapshot-attributes $PROFILE_OPT --region $regx --db-snapshot-identifier $rdssnapshot --query DBSnapshotAttributesResult.DBSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) diff --git a/checks/check_extra725 b/checks/check_extra725 index 3f1edcf3..6424d083 100644 --- a/checks/check_extra725 +++ b/checks/check_extra725 @@ -29,12 +29,12 @@ extra725(){ # "Check if S3 buckets have Object-level logging enabled in CloudTrail " LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --region $REGION --query 'Buckets[*].{Name:Name}' --output text 2>&1) if [[ $(echo "$LIST_OF_BUCKETS" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied trying to list buckets" + textInfo "$REGION: Access Denied trying to list buckets" return fi LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[].TrailARN' --output text 2>&1) if [[ $(echo "$LIST_OF_TRAILS" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied trying to describe trails" + textInfo "$REGION: Access Denied trying to describe trails" return fi if [[ $LIST_OF_BUCKETS ]]; then diff --git a/checks/check_extra726 b/checks/check_extra726 index ac61aaea..c9273cb9 100644 --- a/checks/check_extra726 +++ b/checks/check_extra726 @@ -31,6 +31,10 @@ extra726(){ textInfo "$REGION: Trusted Advisor requires AWS Premium Support Subscription" "$REGION" return fi + if [[ $(echo "$TA_CHECKS_ID" | grep "Could not connect") ]]; then + textInfo "$REGION: Trusted Advisor not available in this region" "$REGION" + return + fi for checkid in $TA_CHECKS_ID; do TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region $REGION --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text) @@ -38,19 +42,19 @@ extra726(){ # Possible results - https://docs.aws.amazon.com/cli/latest/reference/support/describe-trusted-advisor-check-result.html case "$QUERY_TA_CHECK_RESULT" in "ok") - textPass "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in ok state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" + textPass "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "error") - textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in error state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" + textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "warning") - textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in warning state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" + textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "not_available") - textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in not_available state $QUERY_TA_CHECK_RESULT" "u$REGION" "$TA_CHECKS_NAME" + textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "*") - textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in unknown state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" + textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; esac done diff --git a/checks/check_extra727 b/checks/check_extra727 index 86f5dfbd..c6b9a792 100644 --- a/checks/check_extra727 +++ b/checks/check_extra727 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra727='Infrastructure Security' extra727(){ for regx in $REGIONS; do - LIST_SQS=$($AWSCLI sqs list-queues $PROFILE_OPT --region $regx --query QueueUrls --output text |grep -v ^None) + LIST_SQS=$($AWSCLI sqs list-queues $PROFILE_OPT --region $regx --query QueueUrls --output text 2>&1|grep -v ^None ) + if [[ $(echo "$LIST_SQS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list queues" "$regx" + continue + fi if [[ $LIST_SQS ]]; then for queue in $LIST_SQS; do SQS_POLICY=$($AWSCLI sqs get-queue-attributes --queue-url $queue $PROFILE_OPT --region $regx --attribute-names All --query Attributes.Policy) @@ -39,7 +43,7 @@ extra727(){ if [[ $SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION ]]; then SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS=$(echo $SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION \ | jq '"[Principal: " + (.Principal|tostring) + " Action: " + (.Action|tostring) + "]"' ) - textFail "$regx: SQS $queue queue policy with public access: $SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS" "$regx" "$queue" + textFail "$regx: SQS $queue queue policy with public access" "$regx" "$queue" else textInfo "$regx: SQS $queue queue policy with public access but has a Condition" "$regx" "$queue" fi diff --git a/checks/check_extra728 b/checks/check_extra728 index 10ad0e0c..ada64c0f 100644 --- a/checks/check_extra728 +++ b/checks/check_extra728 @@ -27,7 +27,11 @@ CHECK_CAF_EPIC_extra728='Data Protection' extra728(){ for regx in $REGIONS; do - LIST_SQS=$($AWSCLI sqs list-queues $PROFILE_OPT --region $regx --query QueueUrls --output text |grep -v ^None) + LIST_SQS=$($AWSCLI sqs list-queues $PROFILE_OPT --region $regx --query QueueUrls --output text 2>&1|grep -v ^None ) + if [[ $(echo "$LIST_SQS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to list queues" "$regx" + continue + fi if [[ $LIST_SQS ]]; then for queue in $LIST_SQS; do # check if the policy has KmsMasterKeyId therefore SSE enabled diff --git a/checks/check_extra729 b/checks/check_extra729 index 5a839e5e..ca5d5433 100644 --- a/checks/check_extra729 +++ b/checks/check_extra729 @@ -28,7 +28,11 @@ CHECK_CAF_EPIC_extra729='Data Protection' extra729(){ # "Ensure there are no EBS Volumes unencrypted " for regx in $REGIONS; do - LIST_OF_EBS_NON_ENC_VOLUMES=$($AWSCLI ec2 describe-volumes $PROFILE_OPT --region $regx --query 'Volumes[?Encrypted==`false`].VolumeId' --output text) + LIST_OF_EBS_NON_ENC_VOLUMES=$($AWSCLI ec2 describe-volumes $PROFILE_OPT --region $regx --query 'Volumes[?Encrypted==`false`].VolumeId' --output text 2>&1) + if [[ $(echo "$LIST_OF_EBS_NON_ENC_VOLUMES" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then + textInfo "$regx: Access Denied trying to describe volumes" "$regx" + continue + fi if [[ $LIST_OF_EBS_NON_ENC_VOLUMES ]];then for volume in $LIST_OF_EBS_NON_ENC_VOLUMES; do textFail "$regx: $volume is not encrypted!" "$regx" "$volume" diff --git a/checks/check_extra73 b/checks/check_extra73 index 6bb99f69..621ab43e 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -48,7 +48,7 @@ extra73(){ # ACCOUNT_PUBLIC_ACCESS_BLOCK=$($AWSCLI s3control get-public-access-block $PROFILE_OPT --region $REGION --account-id $ACCOUNT_NUM --output json 2>&1) if [[ $(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied getting PublicAccessBlock configuration for AWS account" "$REGION" "$bucket" + textInfo "$REGION: Access Denied getting PublicAccessBlock configuration for AWS account" "$REGION" "$bucket" return fi if [[ $(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | grep NoSuchPublicAccessBlockConfiguration) ]]; then @@ -68,7 +68,7 @@ extra73(){ # ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --output text 2>&1) if [[ $(echo "$ALL_BUCKETS_LIST" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied Trying to List Buckets" "$REGION" "$bucket" + textInfo "$REGION: Access Denied Trying to List Buckets" "$REGION" "$bucket" return fi if [[ "$ALL_BUCKETS_LIST" == "" ]]; then @@ -85,7 +85,7 @@ extra73(){ # BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $REGION --bucket $bucket --output text 2>&1) if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied Trying to Get Bucket Location for $bucket" "$REGION" "$bucket" + textInfo "$REGION: Access Denied Trying to Get Bucket Location for $bucket" "$REGION" "$bucket" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -99,7 +99,7 @@ extra73(){ # BUCKET_PUBLIC_ACCESS_BLOCK=$($AWSCLI s3api get-public-access-block $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output json 2>&1) if [[ $(echo "$BUCKET_PUBLIC_ACCESS_BLOCK" | grep AccessDenied) ]]; then - textFail "$BUCKET_LOCATION: Access Denied Trying to Get Public Access Block for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Public Access Block for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi if [[ $(echo "$BUCKET_PUBLIC_ACCESS_BLOCK" | grep NoSuchPublicAccessBlockConfiguration) ]]; then @@ -119,7 +119,7 @@ extra73(){ # BUCKET_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output json 2>&1) if [[ $(echo "$BUCKET_ACL" | grep AccessDenied) ]]; then - textFail "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Acl for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Acl for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi @@ -140,7 +140,7 @@ extra73(){ # BUCKET_POLICY_STATUS=$($AWSCLI s3api get-bucket-policy-status $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query PolicyStatus.IsPublic --output text 2>&1) if [[ $(echo "$BUCKET_POLICY_STATUS" | grep AccessDenied) ]]; then - textFail "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Policy Status for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Policy Status for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi if [[ $(echo "$BUCKET_POLICY_STATUS" | grep NoSuchBucketPolicy) ]]; then diff --git a/checks/check_extra731 b/checks/check_extra731 index a22d8492..fabb05eb 100644 --- a/checks/check_extra731 +++ b/checks/check_extra731 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra731='Infrastructure Security' extra731(){ for regx in $REGIONS; do - LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query Topics --output text |grep -v ^None) + LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query Topics --output text 2>&1|grep -v ^None ) + if [[ $(echo "$LIST_SNS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list topics" "$regx" + continue + fi if [[ $LIST_SNS ]]; then for topic in $LIST_SNS; do SHORT_TOPIC=$(echo $topic| cut -d: -f6) @@ -39,7 +43,7 @@ extra731(){ if [[ $SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION ]]; then SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS=$(echo $SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION \ | jq '"[Principal: " + (.Principal|tostring) + " Action: " + (.Action|tostring) + "]"' ) - textFail "$regx: SNS topic $SHORT_TOPIC's policy with public access: $SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS" "$regx" "$SHORT_TOPIC" + textFail "$regx: SNS topic $SHORT_TOPIC's policy with public access" "$regx" "$SHORT_TOPIC" else textPass "$regx: SNS topic $SHORT_TOPIC's policy with public access but has a Condition" "$regx" "$SHORT_TOPIC" fi diff --git a/checks/check_extra734 b/checks/check_extra734 index 08646604..d9cacfe5 100644 --- a/checks/check_extra734 +++ b/checks/check_extra734 @@ -30,7 +30,7 @@ extra734(){ for bucket in $LIST_OF_BUCKETS;do BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $REGION --bucket $bucket --output text 2>&1) if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then - textFail "$BUCKET_LOCATION Access Denied Trying to Get Bucket Location for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Location for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -46,7 +46,7 @@ extra734(){ # query to get if has encryption enabled or not RESULT=$($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1) if [[ $(echo "$RESULT" | grep AccessDenied) ]]; then - textFail "$BUCKET_LOCATION: Access Denied Trying to Get Encryption for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Encryption for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi @@ -61,7 +61,7 @@ extra734(){ # get bucket policy $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --region $BUCKET_LOCATION --output text --query Policy > $TEMP_SSE_POLICY_FILE 2>&1 if [[ $(grep AccessDenied $TEMP_SSE_POLICY_FILE) ]]; then - textFail "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Policy for $bucket" "$BUCKET_LOCATION" "$bucket" + textInfo "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Policy for $bucket" "$BUCKET_LOCATION" "$bucket" rm -f $TEMP_SSE_POLICY_FILE continue fi diff --git a/checks/check_extra735 b/checks/check_extra735 index 6b86cc52..1ce59e60 100644 --- a/checks/check_extra735 +++ b/checks/check_extra735 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra735='Data Protection' extra735(){ for regx in $REGIONS; do - LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text) + LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $LIST_OF_RDS_INSTANCES ]];then for rdsinstance in $LIST_OF_RDS_INSTANCES; do IS_ENCRYPTED=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].StorageEncrypted' --output text) diff --git a/checks/check_extra739 b/checks/check_extra739 index 2f998df0..06a67723 100644 --- a/checks/check_extra739 +++ b/checks/check_extra739 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra739='Data Protection' extra739(){ for regx in $REGIONS; do - LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text) + LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe DB instances" "$regx" + continue + fi if [[ $LIST_OF_RDS_INSTANCES ]];then for rdsinstance in $LIST_OF_RDS_INSTANCES; do # if retention is 0 then is disabled diff --git a/checks/check_extra74 b/checks/check_extra74 index 2c57b776..50ed2aa8 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -29,7 +29,11 @@ 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) + 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 diff --git a/checks/check_extra740 b/checks/check_extra740 index d939a305..9b388512 100644 --- a/checks/check_extra740 +++ b/checks/check_extra740 @@ -31,12 +31,21 @@ extra740(){ for regx in ${REGIONS}; do UNENCRYPTED_SNAPSHOTS=$(${AWSCLI} ec2 describe-snapshots ${PROFILE_OPT} \ --region ${regx} --owner-ids ${ACCOUNT_NUM} --output text \ - --query 'Snapshots[?Encrypted==`false`]|[*].{Id:SnapshotId}' \ - | grep -v None 2> /dev/null) + --query 'Snapshots[?Encrypted==`false`]|[*].{Id:SnapshotId}' 2>&1 \ + | grep -v None ) + if [[ $(echo "$UNENCRYPTED_SNAPSHOTS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe snapshots" "$regx" + continue + fi + ENCRYPTED_SNAPSHOTS=$(${AWSCLI} ec2 describe-snapshots ${PROFILE_OPT} \ --region ${regx} --owner-ids ${ACCOUNT_NUM} --output text \ - --query 'Snapshots[?Encrypted==`true`]|[*].{Id:SnapshotId}' \ - | grep -v None 2> /dev/null) + --query 'Snapshots[?Encrypted==`true`]|[*].{Id:SnapshotId}' 2>&1 \ + | grep -v None ) + if [[ $(echo "$ENCRYPTED_SNAPSHOTS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe snapshots" "$regx" + continue + fi typeset -i unencrypted typeset -i encrypted unencrypted=0 diff --git a/checks/check_extra741 b/checks/check_extra741 index 8a7d87e4..5f34a871 100644 --- a/checks/check_extra741 +++ b/checks/check_extra741 @@ -31,7 +31,11 @@ extra741(){ fi for regx in $REGIONS; do - LIST_OF_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query Reservations[*].Instances[*].InstanceId --output text --max-items $MAXITEMS | grep -v None) + 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" diff --git a/checks/check_extra742 b/checks/check_extra742 index 6933c1af..edeaaa9c 100644 --- a/checks/check_extra742 +++ b/checks/check_extra742 @@ -31,7 +31,11 @@ extra742(){ fi for regx in $REGIONS; do - CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --output json) + CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --output json 2>&1) + if [[ $(echo "$CFN_STACKS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe stacks" "$regx" + continue + fi LIST_OF_CFN_STACKS=$(echo $CFN_STACKS | jq -r '.Stacks[].StackName') if [[ $LIST_OF_CFN_STACKS ]];then for stack in $LIST_OF_CFN_STACKS; do diff --git a/checks/check_extra743 b/checks/check_extra743 index b7112cf9..abc15f09 100644 --- a/checks/check_extra743 +++ b/checks/check_extra743 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra743='Data Protection' extra743(){ for regx in $REGIONS; do - LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text) + LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text 2>&1) + if [[ $(echo "$LIST_OF_REST_APIS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_REST_APIS ]];then for api in $LIST_OF_REST_APIS; do API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text) diff --git a/checks/check_extra744 b/checks/check_extra744 index a8672c94..e7dcd10e 100644 --- a/checks/check_extra744 +++ b/checks/check_extra744 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra744='Infrastructure Security' extra744(){ for regx in $REGIONS; do - LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text) + LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text 2>&1) + if [[ $(echo "$LIST_OF_REST_APIS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_REST_APIS ]];then for api in $LIST_OF_REST_APIS; do API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text) diff --git a/checks/check_extra745 b/checks/check_extra745 index 37cb6b17..f6e6fe8b 100644 --- a/checks/check_extra745 +++ b/checks/check_extra745 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra745='Infrastructure Security' extra745(){ for regx in $REGIONS; do - LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text) + LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text 2>&1) + if [[ $(echo "$LIST_OF_REST_APIS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_REST_APIS ]];then for api in $LIST_OF_REST_APIS; do API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text) diff --git a/checks/check_extra746 b/checks/check_extra746 index e2ff570a..d5b6512b 100644 --- a/checks/check_extra746 +++ b/checks/check_extra746 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra746='IAM' extra746(){ for regx in $REGIONS; do - LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text) + LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text 2>&1) + if [[ $(echo "$LIST_OF_REST_APIS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_REST_APIS ]];then for api in $LIST_OF_REST_APIS; do API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text) diff --git a/checks/check_extra747 b/checks/check_extra747 index 80cedad3..ade2b32f 100644 --- a/checks/check_extra747 +++ b/checks/check_extra747 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra747='Logging and Monitoring' extra747(){ for regx in $REGIONS; do - LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text) + LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to get rest APIs" "$regx" + continue + fi if [[ $LIST_OF_RDS_INSTANCES ]];then for rdsinstance in $LIST_OF_RDS_INSTANCES; do # if retention is 0 then is disabled diff --git a/checks/check_extra748 b/checks/check_extra748 index 49c10e76..f9a62174 100644 --- a/checks/check_extra748 +++ b/checks/check_extra748 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra748='Infrastructure Security' extra748(){ for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`0` && ToPort==`65535`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`0` && ToPort==`65535`)) && (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" "$regx" "$SG" diff --git a/checks/check_extra749 b/checks/check_extra749 index 28dbaf46..4f2ee184 100644 --- a/checks/check_extra749 +++ b/checks/check_extra749 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra749='Infrastructure Security' extra749(){ for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`1521` && ToPort>=`1521`)||(FromPort<=`2483` && ToPort>=`2483`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`1521` && ToPort>=`1521`)||(FromPort<=`2483` && ToPort>=`2483`))) && (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 Oracle ports" "$regx" "$SG" diff --git a/checks/check_extra75 b/checks/check_extra75 index 8d24a414..d4abe391 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -29,12 +29,15 @@ 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 | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add') - if [[ $SECURITYGROUPS == "null" ]]; - then + 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 [[ $SECURITYGROUPS == "null" ]]; then continue fi - LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUPS|jq -r 'to_entries|sort_by(.key)|.[]|.key') + LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUPS | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add' |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 diff --git a/checks/check_extra750 b/checks/check_extra750 index 1f0f30c5..14e1f003 100644 --- a/checks/check_extra750 +++ b/checks/check_extra750 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra750='Infrastructure Security' extra750(){ for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3306` && ToPort>=`3306`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3306` && ToPort>=`3306`)) && (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 MySQL port" "$regx" "$SG" diff --git a/checks/check_extra751 b/checks/check_extra751 index 2b31dd91..4eec1a02 100644 --- a/checks/check_extra751 +++ b/checks/check_extra751 @@ -26,7 +26,11 @@ 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) + 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" diff --git a/checks/check_extra752 b/checks/check_extra752 index d60d32f2..4b74116a 100644 --- a/checks/check_extra752 +++ b/checks/check_extra752 @@ -26,7 +26,11 @@ 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) + 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" diff --git a/checks/check_extra753 b/checks/check_extra753 index bd11d24b..8ee93c6b 100644 --- a/checks/check_extra753 +++ b/checks/check_extra753 @@ -26,7 +26,11 @@ 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) + 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" diff --git a/checks/check_extra754 b/checks/check_extra754 index a2252297..ef89bcf8 100644 --- a/checks/check_extra754 +++ b/checks/check_extra754 @@ -26,7 +26,11 @@ 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) + 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" diff --git a/checks/check_extra755 b/checks/check_extra755 index 53ab014b..a766b033 100644 --- a/checks/check_extra755 +++ b/checks/check_extra755 @@ -26,7 +26,11 @@ 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) + 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" diff --git a/checks/check_extra757 b/checks/check_extra757 index dc603afe..55dc81b5 100644 --- a/checks/check_extra757 +++ b/checks/check_extra757 @@ -26,7 +26,11 @@ 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)" + 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 diff --git a/checks/check_extra758 b/checks/check_extra758 index 63129eb3..dd07a60a 100644 --- a/checks/check_extra758 +++ b/checks/check_extra758 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra758='Infrastructure Security' extra758(){ OLDAGE="$(get_date_previous_than_months 12)" for regx in $REGIONS; do - EC2_RUNNING="$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text)" + 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 diff --git a/checks/check_extra759 b/checks/check_extra759 index 533f0445..d804095b 100644 --- a/checks/check_extra759 +++ b/checks/check_extra759 @@ -31,7 +31,11 @@ extra759(){ fi for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text 2>&1) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list functions" "$regx" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then for lambdafunction in $LIST_OF_FUNCTIONS;do LAMBDA_FUNCTION_VARIABLES_FILE="$SECRETS_TEMP_FOLDER/extra759-$lambdafunction-$regx-variables.txt" diff --git a/checks/check_extra76 b/checks/check_extra76 index 3a5d7e54..e606b322 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -27,7 +27,11 @@ 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) + 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" diff --git a/checks/check_extra760 b/checks/check_extra760 index 143ab96e..1d031603 100644 --- a/checks/check_extra760 +++ b/checks/check_extra760 @@ -31,7 +31,11 @@ extra760(){ fi for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text 2>&1) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep AccessDenied) ]]; then + textInfo "$regx: Access Denied trying to list Lambda functions" "$regx" "$lambdafunction" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then for lambdafunction in $LIST_OF_FUNCTIONS;do LAMBDA_FUNCTION_FOLDER="$SECRETS_TEMP_FOLDER/extra760-$lambdafunction-$regx" diff --git a/checks/check_extra761 b/checks/check_extra761 index 7189b473..1e1d2211 100644 --- a/checks/check_extra761 +++ b/checks/check_extra761 @@ -25,16 +25,16 @@ 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' 2>&1) + 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 - textFail "$regx: Newer aws cli needed for get-ebs-encryption-by-default" "$regx" + textInfo "$regx: Newer aws cli needed for get-ebs-encryption-by-default" "$regx" continue fi if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then - textFail "$regx: Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" "$regx" + textInfo "$regx: Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" "$regx" continue fi - if [[ $EBS_DEFAULT_ENCRYPTION == "true" ]];then + if [[ $EBS_DEFAULT_ENCRYPTION == "True" ]];then textPass "$regx: EBS Default Encryption is activated" "$regx" else textFail "$regx: EBS Default Encryption is not activated" "$regx" diff --git a/checks/check_extra762 b/checks/check_extra762 index 28f6c2ab..dfa41438 100644 --- a/checks/check_extra762 +++ b/checks/check_extra762 @@ -18,7 +18,7 @@ CHECK_SEVERITY_extra762="Medium" CHECK_ASFF_RESOURCE_TYPE_extra762="AwsLambdaFunction" CHECK_ALTERNATE_check762="extra762" CHECK_SERVICENAME_extra762="lambda" -CHECK_RISK_extra762=' If you have functions running on a runtime that will be deprecated in the next 60 days; Lambda notifies you by email that you should prepare by migrating your function to a supported runtime. In some cases; such as security issues that require a backwards-incompatible update; or software that does not support a long-term support (LTS) schedule; advance notice might not be possible. After a runtime is deprecated; Lambda might retire it completely at any time by disabling invocation. Deprecated runtimes are not eligible for security updates or technical support.' +CHECK_RISK_extra762='If you have functions running on a runtime that will be deprecated in the next 60 days; Lambda notifies you by email that you should prepare by migrating your function to a supported runtime. In some cases; such as security issues that require a backwards-incompatible update; or software that does not support a long-term support (LTS) schedule; advance notice might not be possible. After a runtime is deprecated; Lambda might retire it completely at any time by disabling invocation. Deprecated runtimes are not eligible for security updates or technical support.' CHECK_REMEDIATION_extra762='Test new runtimes as they are made available. Implement them in production as soon as possible.' CHECK_DOC_extra762='https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html' CHECK_CAF_EPIC_extra762='Infrastructure Security' @@ -30,7 +30,11 @@ extra762(){ OBSOLETE='%(nodejs4.3|nodejs4.3-edge|nodejs6.10|nodejs8.10|dotnetcore1.0|dotnetcore2.0)' for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --output text --query 'Functions[*].{R:Runtime,N:FunctionName}' | tr "\t" "%") + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --output text --query 'Functions[*].{R:Runtime,N:FunctionName}' 2>&1| tr "\t" "%" ) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list functions" "$regx" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then for lambdafunction in $LIST_OF_FUNCTIONS;do fname=$(echo "$lambdafunction" | cut -d'%' -f1) diff --git a/checks/check_extra763 b/checks/check_extra763 index 6cbf5b28..1c44c740 100644 --- a/checks/check_extra763 +++ b/checks/check_extra763 @@ -30,13 +30,13 @@ extra763(){ for bucket in $LIST_OF_BUCKETS;do BUCKET_VERSIONING_ENABLED=$($AWSCLI s3api get-bucket-versioning --bucket $bucket $PROFILE_OPT --query Status --output text 2>&1) if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep AccessDenied) ]]; then - textFail "Access Denied Trying to Get Bucket Versioning for $bucket" + textInfo "Access Denied Trying to Get Bucket Versioning for $bucket" continue fi if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then - textPass "Bucket $bucket has versioning enabled" "us-east-1" "$bucket" + textPass "Bucket $bucket has versioning enabled" "$REGION" "$bucket" else - textFail "Bucket $bucket has versioning disabled!" "us-east-1" "$bucket" + textFail "Bucket $bucket has versioning disabled!" "$REGION" "$bucket" fi done else diff --git a/checks/check_extra764 b/checks/check_extra764 index ab84e553..e3b3a46a 100644 --- a/checks/check_extra764 +++ b/checks/check_extra764 @@ -32,7 +32,7 @@ extra764(){ TEMP_STP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location $PROFILE_OPT --region $REGION --bucket $bucket --output text 2>&1) if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then - textFail "Access Denied Trying to Get Bucket Location for $bucket" + textInfo "Access Denied Trying to Get Bucket Location for $bucket" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -44,7 +44,7 @@ extra764(){ # get bucket policy $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy --region $BUCKET_LOCATION > $TEMP_STP_POLICY_FILE 2>&1 if [[ $(grep AccessDenied $TEMP_STP_POLICY_FILE) ]]; then - textFail "Access Denied Trying to Get Bucket Policy for $bucket" + textInfo "Access Denied Trying to Get Bucket Policy for $bucket" rm -f $TEMP_STP_POLICY_FILE continue fi diff --git a/checks/check_extra765 b/checks/check_extra765 index 34d417cd..91ac7883 100644 --- a/checks/check_extra765 +++ b/checks/check_extra765 @@ -36,7 +36,7 @@ extra765(){ for region in $REGIONS; do LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[*].[repositoryName]" --output text 2>&1) if [[ $(echo "$LIST_ECR_REPOS" | grep AccessDenied) ]]; then - textFail "Access Denied Trying to describe ECR repositories" + textInfo "$region: Access Denied Trying to describe ECR repositories" continue fi if [[ ! -z "$LIST_ECR_REPOS" ]]; then @@ -50,7 +50,7 @@ extra765(){ textFail "$region: ECR repository $repo has scan on push disabled!" "$region" "$repo" ;; "None") - textInfo "$region: ECR repository $repo has no scanOnPush status, newer awscli needed" "$region" "$repo" + textInfo "$region: ECR repository $repo has no scanOnPush status: newer awscli needed" "$region" "$repo" ;; "*") textInfo "$region: ECR repository $repo has unknown scanOnPush status \"$SCAN_ENABLED\"" "$region" "$repo" diff --git a/checks/check_extra768 b/checks/check_extra768 index 5e59c7b8..713530f5 100644 --- a/checks/check_extra768 +++ b/checks/check_extra768 @@ -30,9 +30,13 @@ extra768(){ fi for regx in $REGIONS; do # Get a list of all task definition families first: - FAMILIES=$($AWSCLI ecs list-task-definition-families $PROFILE_OPT --region $regx --status ACTIVE | jq -r .families[]) - if [[ $FAMILIES ]]; then - for FAMILY in $FAMILIES;do + FAMILIES=$($AWSCLI ecs list-task-definition-families $PROFILE_OPT --region $regx --status ACTIVE 2>&1 ) + if [[ $(echo "$FAMILIES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list task definition families" "$regx" + continue + fi + if [[ $(echo $FAMILIES | jq -r .families[]) ]]; then + for FAMILY in $(echo $FAMILIES | jq -r .families[]);do # Get the full task definition arn: TASK_DEFINITION_TEMP=$($AWSCLI ecs list-task-definitions $PROFILE_OPT --region $regx --family-prefix $FAMILY --sort DESC --max-items 1 | jq -r .taskDefinitionArns[0]) # We only care about the task definition name: diff --git a/checks/check_extra769 b/checks/check_extra769 index 6127c646..48c37e53 100644 --- a/checks/check_extra769 +++ b/checks/check_extra769 @@ -27,11 +27,11 @@ extra769(){ for regx in $REGIONS; do LIST_OF_ACCESS_ANALYZERS=$($AWSCLI accessanalyzer list-analyzers $PROFILE_OPT --region $regx --query analyzers[*].arn --output text 2>&1) if [[ $(echo "$LIST_OF_ACCESS_ANALYZERS" | grep -i "argument command: Invalid choice") ]]; then - textInfo "$regx: list-analyzers not supported, newer awscli needed" "$regx" + textInfo "$regx: list-analyzers not supported: newer awscli needed" "$regx" continue fi if [[ $(echo "$LIST_OF_ACCESS_ANALYZERS" | grep -i "AccessDeniedException") ]]; then - textFail "$regx: Access Denied trying to list-analyzers" "$regx" + textInfo "$regx: Access Denied trying to list-analyzers" "$regx" continue fi if [[ $LIST_OF_ACCESS_ANALYZERS ]]; then diff --git a/checks/check_extra77 b/checks/check_extra77 index fcbbd977..4971d243 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -30,11 +30,11 @@ extra77(){ for regx in $REGIONS; do LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query "repositories[*].[repositoryName]" --output text 2>&1) if [[ $(echo "$LIST_ECR_REPOS" | grep AccessDenied) ]]; then - textFail "$regx: Access Denied Trying to describe ECR repositories" "$regx" "$repo" + textInfo "$regx: Access Denied Trying to describe ECR repositories" "$regx" "$repo" continue fi if [[ $(echo "$LIST_ECR_REPOS" | grep SubscriptionRequiredException) ]]; then - textFail "$regx: Subscription Required Exception trying to describe ECR repositories" "$regx" "$repo" + textInfo "$regx: Subscription Required Exception trying to describe ECR repositories" "$regx" "$repo" continue fi if [[ ! -z "$LIST_ECR_REPOS" ]]; then @@ -42,7 +42,7 @@ extra77(){ TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX) $AWSCLI ecr get-repository-policy $PROFILE_OPT --region $regx --repository-name $repo --query "policyText" --output text > $TEMP_POLICY_FILE 2>&1 if [[ $(grep AccessDenied $TEMP_POLICY_FILE) ]]; then - textFail "$regx: $repo Access Denied for get-repository-policy" "$regx" "$repo" + textInfo "$regx: Access Denied to get repository policy for repo $repo" "$regx" "$repo" rm -f $TEMP_POLICY_FILE continue fi diff --git a/checks/check_extra770 b/checks/check_extra770 index e2c3abf7..6975c22f 100644 --- a/checks/check_extra770 +++ b/checks/check_extra770 @@ -26,7 +26,11 @@ 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) + 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; }') diff --git a/checks/check_extra772 b/checks/check_extra772 index c56a7c32..560cc1ad 100644 --- a/checks/check_extra772 +++ b/checks/check_extra772 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra772='Infrastructure Security' extra772(){ for region in $REGIONS; do - EIP_DUMP=$($AWSCLI ec2 describe-addresses ${PROFILE_OPT} --region $region --output json) + 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 diff --git a/checks/check_extra775 b/checks/check_extra775 index bc47823f..7b6f5f53 100644 --- a/checks/check_extra775 +++ b/checks/check_extra775 @@ -30,7 +30,11 @@ extra775(){ fi for regx in $REGIONS; do - LIST_OF_EC2_AUTOSCALING=$($AWSCLI autoscaling describe-launch-configurations $PROFILE_OPT --region $regx --query LaunchConfigurations[*].LaunchConfigurationName --output text --max-items $MAXITEMS | grep -v None) + LIST_OF_EC2_AUTOSCALING=$($AWSCLI autoscaling describe-launch-configurations $PROFILE_OPT --region $regx --query LaunchConfigurations[*].LaunchConfigurationName --output text --max-items $MAXITEMS 2>&1 | grep -v None ) + if [[ $(echo "$LIST_OF_EC2_AUTOSCALING" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe launch configurations" "$regx" + continue + fi if [[ $LIST_OF_EC2_AUTOSCALING ]];then for autoscaling_configuration in $LIST_OF_EC2_AUTOSCALING; do EC2_AUTOSCALING_USERDATA_FILE="$SECRETS_TEMP_FOLDER/extra775-$autoscaling_configuration-userData.decoded" diff --git a/checks/check_extra776 b/checks/check_extra776 index 9212d084..36fc793d 100644 --- a/checks/check_extra776 +++ b/checks/check_extra776 @@ -42,7 +42,7 @@ extra776(){ for region in $REGIONS; do LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[*].[repositoryName]" --output text 2>&1) if [[ $(echo "$LIST_ECR_REPOS" | grep AccessDenied) ]]; then - textFail "Access Denied Trying to describe ECR repositories" + textInfo "$region: Access Denied trying to describe ECR repositories" continue fi if [[ ! -z "$LIST_ECR_REPOS" ]]; then diff --git a/checks/check_extra777 b/checks/check_extra777 index 4cfc026a..b7d459df 100644 --- a/checks/check_extra777 +++ b/checks/check_extra777 @@ -15,7 +15,7 @@ # 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 many ingress or egress rules " +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" @@ -35,8 +35,11 @@ extra777(){ ${PROFILE_OPT} \ --region ${regx} \ --query 'SecurityGroups[*].GroupId' \ - --output text | xargs - ) + --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 @@ -58,6 +61,8 @@ extra777(){ 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 diff --git a/checks/check_extra778 b/checks/check_extra778 index 0966ee74..c1771752 100644 --- a/checks/check_extra778 +++ b/checks/check_extra778 @@ -48,8 +48,11 @@ extra778(){ --filter "Name=group-id,Values=${SECURITY_GROUP}" \ --query "SecurityGroups[*].${DIRECTION_FILTER}[*].IpRanges[*].CidrIp" \ --region ${REGION} \ - --output text | xargs - ) + --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 @@ -58,6 +61,8 @@ extra778(){ # 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 @@ -68,8 +73,11 @@ extra778(){ ${PROFILE_OPT} \ --region ${regx} \ --query 'SecurityGroups[*].GroupId' \ - --output text | xargs - ) + --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}" diff --git a/checks/check_extra779 b/checks/check_extra779 index ccb95abe..c835eb4c 100644 --- a/checks/check_extra779 +++ b/checks/check_extra779 @@ -31,7 +31,11 @@ extra779(){ 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}") + --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 diff --git a/checks/check_extra78 b/checks/check_extra78 index bc32dc1c..ad8ec1bb 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -28,7 +28,11 @@ CHECK_CAF_EPIC_extra78='Data Protection' extra78(){ # "Ensure there are no Public Accessible RDS instances " for regx in $REGIONS; do - LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true` && DBInstanceStatus==`"available"`].[DBInstanceIdentifier,Endpoint.Address]' --output text) + LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true` && DBInstanceStatus==`"available"`].[DBInstanceIdentifier,Endpoint.Address]' --output text 2>&1) + if [[ $(echo "$LIST_OF_RDS_PUBLIC_INSTANCES" | grep AccessDenied) ]]; then + textInfo "$regx: Access Denied Trying to describe DB instances" "$regx" + continue + fi if [[ $LIST_OF_RDS_PUBLIC_INSTANCES ]];then while read -r rds_instance;do RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') diff --git a/checks/check_extra780 b/checks/check_extra780 index d835d626..7cd183b3 100644 --- a/checks/check_extra780 +++ b/checks/check_extra780 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra780='IAM' extra780(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_COGNITO_ENABLED=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.CognitoOptions.Enabled' --output text|grep -i true) diff --git a/checks/check_extra781 b/checks/check_extra781 index 38a4899a..55bb4748 100644 --- a/checks/check_extra781 +++ b/checks/check_extra781 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra781='Data Protection' extra781(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_ENCREST_ENABLED=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.EncryptionAtRestOptions.Enabled' --output text|grep -i true) diff --git a/checks/check_extra782 b/checks/check_extra782 index f6babb04..78afc60e 100644 --- a/checks/check_extra782 +++ b/checks/check_extra782 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra782='Data Protection' extra782(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_NODETOENCR_ENABLED=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.NodeToNodeEncryptionOptions.Enabled' --output text|grep -i true) diff --git a/checks/check_extra783 b/checks/check_extra783 index ec8005e2..56d942c2 100644 --- a/checks/check_extra783 +++ b/checks/check_extra783 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra783='Data Protection' extra783(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_ENFORCEHTTPS_ENABLED=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.DomainEndpointOptions.EnforceHTTPS' --output text|grep -i true) diff --git a/checks/check_extra784 b/checks/check_extra784 index 3a200968..dea6e510 100644 --- a/checks/check_extra784 +++ b/checks/check_extra784 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra784='IAM' extra784(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_INTERNALDB_ENABLED=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.AdvancedSecurityOptions.InternalUserDatabaseEnabled' --output text|grep -i true) diff --git a/checks/check_extra785 b/checks/check_extra785 index e47e0a6f..6a8a2495 100644 --- a/checks/check_extra785 +++ b/checks/check_extra785 @@ -30,7 +30,11 @@ CHECK_CAF_EPIC_extra785='Infrastructure Security' extra785(){ for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do CHECK_IF_UPDATE_AVAILABLE_AND_VERSION=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.[ServiceSoftwareOptions.UpdateAvailable,ElasticsearchVersion]' --output text) diff --git a/checks/check_extra786 b/checks/check_extra786 index 11643e4a..76430778 100644 --- a/checks/check_extra786 +++ b/checks/check_extra786 @@ -28,7 +28,11 @@ extra786(){ 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 + --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 diff --git a/checks/check_extra787 b/checks/check_extra787 index ef61f44f..30b8a5ee 100644 --- a/checks/check_extra787 +++ b/checks/check_extra787 @@ -34,7 +34,11 @@ extra787(){ for regx in $REGIONS; do # create 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}") + --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 diff --git a/checks/check_extra788 b/checks/check_extra788 index b407ccac..50a9fdf3 100644 --- a/checks/check_extra788 +++ b/checks/check_extra788 @@ -29,7 +29,11 @@ extra788(){ # "Check if Elasticsearch Service domains allow open access " for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text 2>&1) + if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list domain names" "$regx" + continue + fi if [[ $LIST_OF_DOMAINS ]]; then for domain in $LIST_OF_DOMAINS;do TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX) diff --git a/checks/check_extra789 b/checks/check_extra789 index 66fe6250..b4d90f23 100644 --- a/checks/check_extra789 +++ b/checks/check_extra789 @@ -32,8 +32,11 @@ extra789(){ ${PROFILE_OPT} \ --query "ServiceDetails[?Owner=='${ACCOUNT_NUM}'].ServiceId" \ --region ${regx} \ - --output text | xargs - ) + --output text | xargs 2>&1) + if [[ $(echo "$ENDPOINT_SERVICES_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe VPC endpoint services" "$regx" + continue + fi for ENDPOINT_SERVICE_ID in ${ENDPOINT_SERVICES_IDS}; do diff --git a/checks/check_extra79 b/checks/check_extra79 index bcb414bb..918db5d1 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -28,8 +28,16 @@ CHECK_CAF_EPIC_extra79='Data Protection' extra79(){ # "Check for internet facing Elastic Load Balancers " for regx in $REGIONS; do - LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) - LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) + LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text 2>&1) + if [[ $(echo "$LIST_OF_PUBLIC_ELBS" | grep AccessDenied) ]]; then + textInfo "$regx: Access Denied Trying to describe load balancers" "$regx" + continue + fi + LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text 2>&1) + if [[ $(echo "$LIST_OF_PUBLIC_ELBSV2" | grep AccessDenied) ]]; then + textInfo "$regx: Access Denied Trying to describe load balancers" "$regx" + continue + fi LIST_OF_ALL_ELBS=$( echo $LIST_OF_PUBLIC_ELBS; echo $LIST_OF_PUBLIC_ELBSV2) LIST_OF_ALL_ELBS_PER_LINE=$( echo $LIST_OF_ALL_ELBS| xargs -n2 ) if [[ $LIST_OF_ALL_ELBS ]];then diff --git a/checks/check_extra790 b/checks/check_extra790 index f2680c78..d562a40c 100644 --- a/checks/check_extra790 +++ b/checks/check_extra790 @@ -32,8 +32,11 @@ extra790(){ ${PROFILE_OPT} \ --query "ServiceDetails[?Owner=='${ACCOUNT_NUM}'].ServiceId" \ --region ${regx} \ - --output text | xargs - ) + --output text | xargs 2>&1) + if [[ $(echo "$ENDPOINT_SERVICES_IDS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe VPC endpoint services" "$regx" + continue + fi for ENDPOINT_SERVICE_ID in ${ENDPOINT_SERVICES_IDS}; do ENDPOINT_PERMISSIONS_LIST=$(${AWSCLI} ec2 describe-vpc-endpoint-service-permissions \ diff --git a/checks/check_extra792 b/checks/check_extra792 index 04b36bf3..ae22adc4 100644 --- a/checks/check_extra792 +++ b/checks/check_extra792 @@ -27,8 +27,16 @@ CHECK_CAF_EPIC_extra792='Data Protection' extra792(){ # "Check if Elastic Load Balancers have insecure SSL ciphers " for regx in $REGIONS; do - LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1|xargs -n1 ) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1|xargs -n1 ) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then if [[ $LIST_OF_ELBS ]]; then # https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-ssl-security-policy.html#ssl-ciphers @@ -37,7 +45,7 @@ extra792(){ ELBSECURECIPHERS=("Protocol-TLSv1.2" "Protocol-TLSv1.1" "Protocol-TLSv1" "ECDHE-ECDSA-AES128-GCM-SHA256" "ECDHE-RSA-AES128-GCM-SHA256" "ECDHE-ECDSA-AES128-SHA256" "ECDHE-RSA-AES128-SHA256" "ECDHE-ECDSA-AES128-SHA" "ECDHE-RSA-AES128-SHA" "ECDHE-ECDSA-AES256-GCM-SHA384" "ECDHE-RSA-AES256-GCM-SHA384" "ECDHE-ECDSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA" "ECDHE-ECDSA-AES256-SHA" "AES128-GCM-SHA256" "AES128-SHA256" "AES128-SHA" "AES256-GCM-SHA384" "AES256-SHA256" "AES256-SHA" "Server-Defined-Cipher-Order") for elb in $LIST_OF_ELBS; do - ELB_LISTENERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0]") + ELB_LISTENERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0]" --output json) ELB_PROTOCOLS=$(echo $ELB_LISTENERS | jq -r '.ListenerDescriptions[].Listener.Protocol') if [[ $(echo $ELB_PROTOCOLS | grep HTTPS) || $(echo $ELB_PROTOCOLS | grep SSL) ]]; then @@ -90,7 +98,7 @@ extra792(){ elbname=$elbarn fi - ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]") + ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]" --output json) ELBV2_PROTOCOLS=$(echo $ELBV2_LISTENERS | jq -r '.[].Protocol') diff --git a/checks/check_extra793 b/checks/check_extra793 index 413a8a47..505c6511 100644 --- a/checks/check_extra793 +++ b/checks/check_extra793 @@ -27,8 +27,16 @@ CHECK_CAF_EPIC_extra793='Data Protection' extra793(){ # "Check if Elastic Load Balancers have encrypted listeners " for regx in $REGIONS; do - LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?(Type == `application`)].LoadBalancerArn' --output text|xargs -n1) + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1|xargs -n1) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1|xargs -n1) + if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to describe load balancers" "$regx" + continue + fi if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then if [[ $LIST_OF_ELBS ]]; then ENCRYPTEDPROTOCOLS=("HTTPS" "SSL") diff --git a/checks/check_extra794 b/checks/check_extra794 index ef6f2aee..ef2b5c50 100644 --- a/checks/check_extra794 +++ b/checks/check_extra794 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra794='Logging and Monitoring' extra794(){ for regx in $REGIONS; do - CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text) + CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text 2>&1) + if [[ $(echo "$CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list EKS clusters" "$regx" + continue + fi if [[ $CLUSTERS ]]; then for CLUSTER in $CLUSTERS;do CLUSTERDEF=$($AWSCLI eks describe-cluster $PROFILE_OPT --region $regx --name $CLUSTER --query 'cluster.logging.clusterLogging[0]') @@ -35,7 +39,7 @@ extra794(){ if [[ $(echo $TYPES | egrep "api.*audit.*authenticator.*controllerManager.*scheduler") ]]; then textPass "$regx: Control plane logging enabled and correctly configured for EKS cluster $CLUSTER" "$regx" "$CLUSTER" else - textFail "$regx: Control plane logging enabled, but not all log types collected for EKS cluster $CLUSTER" "$regx" "$CLUSTER" + textFail "$regx: Control plane logging enabled; not all log types collected for EKS cluster $CLUSTER" "$regx" "$CLUSTER" fi else textFail "$regx: Control plane logging is not enabled for EKS cluster $CLUSTER" "$regx" "$CLUSTER" diff --git a/checks/check_extra795 b/checks/check_extra795 index 7030d741..fa2398a3 100644 --- a/checks/check_extra795 +++ b/checks/check_extra795 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra795='Infrastructure Security' extra795(){ for regx in $REGIONS; do - CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text) + CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text 2>&1) + if [[ $(echo "$CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list EKS clusters" "$regx" + continue + fi if [[ $CLUSTERS ]]; then for CLUSTER in $CLUSTERS;do CLUSTERDEF=$($AWSCLI eks describe-cluster $PROFILE_OPT --region $regx --name $CLUSTER --query 'cluster.resourcesVpcConfig') diff --git a/checks/check_extra796 b/checks/check_extra796 index 34789c74..70611d9e 100644 --- a/checks/check_extra796 +++ b/checks/check_extra796 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra796='Infrastructure Security' extra796(){ for regx in $REGIONS; do - CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text) + CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text 2>&1) + if [[ $(echo "$CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list EKS clusters" "$regx" + continue + fi if [[ $CLUSTERS ]]; then for CLUSTER in $CLUSTERS;do CLUSTERDEF=$($AWSCLI eks describe-cluster $PROFILE_OPT --region $regx --name $CLUSTER --query 'cluster.resourcesVpcConfig') diff --git a/checks/check_extra797 b/checks/check_extra797 index 473c5376..beb28f76 100644 --- a/checks/check_extra797 +++ b/checks/check_extra797 @@ -25,7 +25,11 @@ CHECK_CAF_EPIC_extra797='Data Protection' extra797(){ for regx in $REGIONS; do - CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text) + CLUSTERS=$($AWSCLI eks list-clusters $PROFILE_OPT --region $regx --query 'clusters[]' --output text 2>&1) + if [[ $(echo "$CLUSTERS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list EKS clusters" "$regx" + continue + fi if [[ $CLUSTERS ]]; then for CLUSTER in $CLUSTERS;do ENC_CONFIG=$($AWSCLI eks describe-cluster $PROFILE_OPT --region $regx --name $CLUSTER --query 'cluster.encryptionConfig') diff --git a/checks/check_extra798 b/checks/check_extra798 index 0e14d22a..21604e16 100644 --- a/checks/check_extra798 +++ b/checks/check_extra798 @@ -26,7 +26,11 @@ CHECK_CAF_EPIC_extra798='Infrastructure Security' extra798(){ for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --output text --query 'Functions[*].FunctionName') + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --output text --query 'Functions[*].FunctionName' 2>&1) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then + textInfo "$regx: Access Denied trying to list functions" "$regx" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then for lambdafunction in $LIST_OF_FUNCTIONS; do # get the policy per function diff --git a/checks/check_sample b/checks/check_sample index b7b284bf..1ec39a35 100644 --- a/checks/check_sample +++ b/checks/check_sample @@ -23,16 +23,20 @@ # --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' \ # --metric-transformations metricName=CloudTrailEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 - # CHECK_ID_checkN="N.N" # CHECK_TITLE_checkN="[checkN] Description " # CHECK_SCORED_checkN="NOT_SCORED" # CHECK_CIS_LEVEL_checkN="EXTRA" -# CHECK_SEVERITY_check="Medium" +# CHECK_SEVERITY_checkNN="Medium" # CHECK_ASFF_RESOURCE_TYPE_checkN="AwsAccount" # Choose appropriate value from https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#asff-resources # CHECK_ALTERNATE_checkN="extraN" -# CHECK_SERVICENAME_checkN="service" # get service short name from `curl -s https://api.regional-table.region-services.aws.a2z.com/index.json | jq -r '.prices[] | .id' | awk -F: '{ print $1 }' | sort -u` -# +# CHECK_SERVICENAME_checkN="service" # get service short name from `curl -s https://api.regional-table.region-services.aws.a2z.com/index.json | jq -r '.prices[] | .id' | awk -F: '{ print $1 }' | sort -u` +# CHECK_RISK_checkN="" +# CHECK_REMEDIATION_checkN="" +# CHECK_DOC_checkN="" +# CHECK_CAF_EPIC_checkN="" + +# Example of regional resource # extraN(){ # # "Description " # textInfo "Looking for instances in all regions... " @@ -42,10 +46,28 @@ # while read -r instance;do # INSTANCE_ID=$(echo $instance | awk '{ print $1; }') # PUBLIC_IP=$(echo $instance | awk '{ print $2; }') -# textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" +# textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" "$INSTANCE_ID" # done <<< "$LIST_OF_PUBLIC_INSTANCES" # else # textPass "$regx: no Internet Facing EC2 Instances found" "$regx" # fi # done # } + +# Example of global resource +# extraN(){ +# # "Description " +# LIST_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --query 'DistributionList.Items[*].Id' --output text |grep -v ^None) +# if [[ $LIST_DISTRIBUTIONS ]]; then +# for dist in $LIST_DISTRIBUTIONS; do +# GEO_ENABLED=$($AWSCLI cloudfront get-distribution-config $PROFILE_OPT --id $dist --query DistributionConfig.Restrictions.GeoRestriction.RestrictionType --output text) +# if [[ $GEO_ENABLED == "none" ]]; then +# textFail "$REGION: CloudFront distribution $dist has not Geo restrictions" "$REGION" "$dist" +# else +# textPass "$REGION: CloudFront distribution $dist has Geo restrictions enabled" "$REGION" "$dist" +# fi +# done +# else +# textInfo "$REGION: No CloudFront distributions found" +# fi +# } diff --git a/groups/group25_FTR b/groups/group25_FTR index 7ca694f7..fd0f8bfd 100644 --- a/groups/group25_FTR +++ b/groups/group25_FTR @@ -14,8 +14,8 @@ GROUP_ID[25]='ftr' GROUP_NUMBER[25]='25.0' GROUP_TITLE[25]='Amazon FTR related security checks - [ftr] ******************' -GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called -GROUP_CHECKS[9]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check111,check112,check113,check117,check118,check122,check21,check22,extra759,extra760,extra768,extra775,extra797,extra7141,extra73' +GROUP_RUN_BY_DEFAULT[25]='N' # run it when execute_all is called +GROUP_CHECKS[25]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check111,check112,check113,check117,check118,check122,check21,check22,extra759,extra760,extra768,extra775,extra797,extra7141,extra73' # Checks from AWS FTR https://apn-checklists.s3.amazonaws.com/foundational/partner-hosted/partner-hosted/CVLHEC5X7.html # 1.1 [check11] Avoid the use of the root account - iam [High] diff --git a/groups/group7_extras b/groups/group7_extras index 60cffc06..eeb1d031 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,9 +15,9 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - all non CIS specific checks - [extras] ****************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159,extra7160,extra7161,extra7162,extra7163,extra7164,extra7165,extra7166,extra7167,extra7168,extra7169,extra7170,extra7171' -# Extras 759 and 760 (lambda variables and code secrets finder are not included) +# Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` # Extras 789 and 790 VPC trust boundaries are not included by default in Extras diff --git a/iam/create_role_to_assume_cfn.yaml b/iam/create_role_to_assume_cfn.yaml index 1e1140a1..9a0c9f08 100644 --- a/iam/create_role_to_assume_cfn.yaml +++ b/iam/create_role_to_assume_cfn.yaml @@ -62,5 +62,9 @@ Resources: - 'tag:GetTagKeys' - 'lambda:GetFunction' - 'glue:GetConnections' + - 'glue:GetSecurityConfiguration' + - 'glue:SearchTables' - 's3:GetAccountPublicAccessBlock' + - 'shield:GetSubscriptionState' + - 'shield:DescribeProtection' Resource: '*' diff --git a/iam/prowler-additions-policy.json b/iam/prowler-additions-policy.json index f0285c24..6921d3ab 100644 --- a/iam/prowler-additions-policy.json +++ b/iam/prowler-additions-policy.json @@ -8,10 +8,13 @@ "ecr:Describe*", "support:Describe*", "tag:GetTagKeys", - "lambda:GetFunction", + "lambda:GetFunction", "glue:GetConnections", + "glue:GetSecurityConfiguration", "glue:SearchTables", - "s3:GetAccountPublicAccessBlock" + "s3:GetAccountPublicAccessBlock", + "shield:GetSubscriptionState", + "shield:DescribeProtection" ], "Resource": "*", "Effect": "Allow", diff --git a/include/assume_role b/include/assume_role index 95bd3e00..7f94b4fd 100644 --- a/include/assume_role +++ b/include/assume_role @@ -11,9 +11,16 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. -# both variables are mandatory to be set together assume_role(){ - if [[ -z $ROLE_TO_ASSUME ]]; then + + PROFILE_OPT=$PROFILE_OPT_BAK + if [[ "${PROFILE_OPT}" = "" ]]; then + # If profile is not defined, restore original credentials from environment variables, if they exists! + restoreInitialAWSCredentials + fi + + # Both variables are mandatory to be set together + if [[ -z $ROLE_TO_ASSUME || -z $ACCOUNT_TO_ASSUME ]]; then echo "$OPTRED ERROR!$OPTNORMAL - Both Account ID (-A) and IAM Role to assume (-R) must be set" exit 1 fi @@ -28,6 +35,7 @@ assume_role(){ # temporary file where to store credentials TEMP_STS_ASSUMED_FILE=$(mktemp -t prowler.sts_assumed-XXXXXX) + TEMP_STS_ASSUMED_ERROR=$(mktemp -t prowler.sts_assumed-XXXXXX) # check if role arn or role name if [[ $ROLE_TO_ASSUME == arn:* ]]; then @@ -36,57 +44,70 @@ assume_role(){ PROWLER_ROLE=arn:${AWS_PARTITION}:iam::$ACCOUNT_TO_ASSUME:role/$ROLE_TO_ASSUME fi - #Check if external ID has bee provided if so execute with external ID if not ignore - if [[ -z $ROLE_EXTERNAL_ID ]]; then - # assume role command - $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --region $REGION_FOR_STS \ - --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE 2>&1 - else - $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --duration-seconds $SESSION_DURATION_TO_ASSUME \ - --region $REGION_FOR_STS \ - --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE 2>&1 - fi - if [[ $(grep AccessDenied $TEMP_STS_ASSUMED_FILE) ]]; then - textFail "Access Denied assuming role $PROWLER_ROLE" - EXITCODE=1 - exit $EXITCODE - elif [[ "$(grep MaxSessionDuration $TEMP_STS_ASSUMED_FILE)" ]]; then - textFail "The requested DurationSeconds exceeds the MaxSessionDuration set for the role ${PROWLER_ROLE}" - EXITCODE=1 - exit $EXITCODE + # Check if external ID has bee provided if so execute with external ID if not ignore + ROLE_EXTERNAL_ID_OPTION="" + if [[ -n "${ROLE_EXTERNAL_ID}" ]]; then + ROLE_EXTERNAL_ID_OPTION="--external-id ${ROLE_EXTERNAL_ID}" fi - # assume role command - #$AWSCLI $PROFILE_OPT sts assume-role --role-arn arn:${AWS_PARTITION}:iam::$ACCOUNT_TO_ASSUME:role/$ROLE_TO_ASSUME \ - # --role-session-name ProwlerAssessmentSession \ - # --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE - - # if previous command fails exit with the given error from aws-cli - # this is likely to be due to session duration limit of 1h in case - # of assume role chaining: - # "The requested DurationSeconds exceeds the 1 hour session limit - # for roles assumed by role chaining." - # https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html - if [[ $? != 0 ]];then - exit 1 + # Assume role + if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ + --role-session-name ProwlerAssessmentSession \ + --duration-seconds $SESSION_DURATION_TO_ASSUME \ + --region $REGION_FOR_STS \ + "${ROLE_EXTERNAL_ID_OPTION}" > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" + then + STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" + textFail "${STS_ERROR}" + EXITCODE=1 + exit $EXITCODE fi - + + # echo FILE WITH TEMP CREDS: $TEMP_STS_ASSUMED_FILE + # The profile shouldn't be used for CLI PROFILE="" - PROFILE_OPT="" + PROFILE_OPT="" + + # Set AWS environment variables with assumed role credentials + ASSUME_AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' "${TEMP_STS_ASSUMED_FILE}") + export AWS_ACCESS_KEY_ID=$ASSUME_AWS_ACCESS_KEY_ID + ASSUME_AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SECRET_ACCESS_KEY=$ASSUME_AWS_SECRET_ACCESS_KEY + ASSUME_AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SESSION_TOKEN=$ASSUME_AWS_SESSION_TOKEN + ASSUME_AWS_SESSION_EXPIRATION=$(jq -r '.Credentials.Expiration | sub("\\+00:00";"Z") | fromdateiso8601' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SESSION_EXPIRATION=$ASSUME_AWS_SESSION_EXPIRATION + # echo TEMP AWS_ACCESS_KEY_ID: $ASSUME_AWS_ACCESS_KEY_ID + # echo TEMP AWS_SECRET_ACCESS_KEY: $ASSUME_AWS_SECRET_ACCESS_KEY + # echo TEMP AWS_SESSION_TOKEN: $ASSUME_AWS_SESSION_TOKEN + # echo EXPIRATION EPOCH TIME: $ASSUME_AWS_SESSION_EXPIRATION - # set env variables with assumed role credentials - export AWS_ACCESS_KEY_ID=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.AccessKeyId') - export AWS_SECRET_ACCESS_KEY=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SecretAccessKey') - export AWS_SESSION_TOKEN=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SessionToken') - export AWS_SESSION_EXPIRATION=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration | sub("\\+00:00";"Z") | fromdateiso8601') cleanSTSAssumeFile } cleanSTSAssumeFile() { rm -fr "${TEMP_STS_ASSUMED_FILE}" -} \ No newline at end of file + rm -fr "${TEMP_STS_ASSUMED_ERROR}" +} + +backupInitialAWSCredentials() { + + if [[ $(printenv AWS_ACCESS_KEY_ID) && $(printenv AWS_SECRET_ACCESS_KEY) && $(printenv AWS_SESSION_TOKEN) ]]; then + INITIAL_AWS_ACCESS_KEY_ID=$(printenv AWS_ACCESS_KEY_ID) + INITIAL_AWS_SECRET_ACCESS_KEY=$(printenv AWS_SECRET_ACCESS_KEY) + INITIAL_AWS_SESSION_TOKEN=$(printenv AWS_SESSION_TOKEN) + fi +} + +restoreInitialAWSCredentials() { + if [[ $INITIAL_AWS_ACCESS_KEY_ID && $INITIAL_AWS_SECRET_ACCESS_KEY && $INITIAL_AWS_SESSION_TOKEN ]]; then + export AWS_ACCESS_KEY_ID=$INITIAL_AWS_ACCESS_KEY_ID + export AWS_SECRET_ACCESS_KEY=$INITIAL_AWS_SECRET_ACCESS_KEY + export AWS_SESSION_TOKEN=$INITIAL_AWS_SESSION_TOKEN + else + unset AWS_ACCESS_KEY_ID + unset AWS_SECRET_ACCESS_KEY + unset AWS_SESSION_TOKEN + fi +} diff --git a/include/aws_profile_loader b/include/aws_profile_loader index a2e446d3..e79cea87 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -45,7 +45,8 @@ else PROFILE="default" PROFILE_OPT="--profile $PROFILE" fi - +# Backing up $PROFILE_OPT needed to renew assume_role +PROFILE_OPT_BAK=$PROFILE_OPT # Set default region by aws config, fall back to us-east-1 REGION_CONFIG=$(aws configure get region) if [[ $REGION_OPT ]]; then diff --git a/include/check3x b/include/check3x index ea29047e..29de748e 100644 --- a/include/check3x +++ b/include/check3x @@ -18,7 +18,7 @@ check3x(){ # be based only on CloudTrail tail with CloudWatchLog configuration. DESCRIBE_TRAILS_CACHE=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[?CloudWatchLogsLogGroupArn != `null`]' 2>&1) if [[ $(echo "$DESCRIBE_TRAILS_CACHE" | grep AccessDenied) ]]; then - textFail "$REGION: Access Denied trying to describe trails in $REGION" "$REGION" + textInfo "$REGION: Access Denied trying to describe trails in $REGION" "$REGION" return fi diff --git a/include/outputs_bucket b/include/outputs_bucket index f89a7fd4..621b9fca 100644 --- a/include/outputs_bucket +++ b/include/outputs_bucket @@ -15,18 +15,18 @@ if [[ $OUTPUT_BUCKET ]]; then # output mode has to be set to other than text if [[ "${MODES[@]}" =~ "html" ]] || [[ "${MODES[@]}" =~ "csv" ]] || [[ "${MODES[@]}" =~ "json" ]] || [[ "${MODES[@]}" =~ "json-asff" ]]; then OUTPUT_BUCKET_WITHOUT_FOLDERS=$(echo $OUTPUT_BUCKET | awk -F'/' '{ print $1 }') - OUTPUT_BUCKET_STATUS=$($AWSCLI s3api head-bucket --bucket "$OUTPUT_BUCKET" 2>&1 || true) - if [[ ! -z $OUTPUT_BUCKET_STATUS ]]; then - echo "$OPTRED ERROR!$OPTNORMAL wrong bucket name or not right permissions." - exit 1 - else +# OUTPUT_BUCKET_STATUS=$($AWSCLI s3api head-bucket --bucket "$OUTPUT_BUCKET" 2>&1 || true) +# if [[ -z $OUTPUT_BUCKET_STATUS ]]; then +# echo "$OPTRED ERROR!$OPTNORMAL wrong bucket name or not right permissions." +# exit 1 +# else # need to make sure last / is not set to avoid // in S3 if [[ $OUTPUT_BUCKET != *"/" ]]; then OUTPUT_BUCKET="$OUTPUT_BUCKET" else OUTPUT_BUCKET=${OUTPUT_BUCKET::-1} fi - fi +# fi else echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) has to be set as well. Use -h for help." exit 1 @@ -38,19 +38,19 @@ copyToS3(){ # and processing by Quicksight or others. if [[ $OUTPUT_BUCKET ]]; then if [[ "${MODES[@]}" =~ "csv" ]]; then - $AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_CSV \ + $AWSCLI $PROFILE_OPT s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_CSV \ s3://$OUTPUT_BUCKET/csv/ --acl bucket-owner-full-control fi if [[ "${MODES[@]}" =~ "html" ]]; then - $AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_HTML \ + $AWSCLI $PROFILE_OPT s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_HTML \ s3://$OUTPUT_BUCKET/html/ --acl bucket-owner-full-control fi if [[ "${MODES[@]}" =~ "json" ]]; then - $AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_JSON \ + $AWSCLI $PROFILE_OPT s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_JSON \ s3://$OUTPUT_BUCKET/json/ --acl bucket-owner-full-control fi if [[ "${MODES[@]}" =~ "json-asff" ]]; then - $AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_ASFF \ + $AWSCLI $PROFILE_OPT s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_ASFF \ s3://$OUTPUT_BUCKET/json-asff/ --acl bucket-owner-full-control fi fi diff --git a/include/securityhub_integration b/include/securityhub_integration index 74a1c35d..92151d45 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -42,29 +42,48 @@ checkSecurityHubCompatibility(){ resolveSecurityHubPreviousFails(){ # Move previous check findings RecordState to ARCHIVED (as prowler didn't re-detect them) + SH_TEMP_FOLDER="$PROWLER_DIR/SH-$ACCOUNT_NUM" + if [[ ! -d $SH_TEMP_FOLDER ]]; then + # this folder is deleted once the security hub update is completed + mkdir "$SH_TEMP_FOLDER" + fi for regx in $REGIONS; do - + REGION_FOLDER="$SH_TEMP_FOLDER/$regx" + if [[ ! -d $REGION_FOLDER ]]; then + mkdir "$REGION_FOLDER" + fi local check="$1" NEW_TIMESTAMP=$(get_iso8601_timestamp) FILTER="{\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"EQUALS\"}],\"RecordState\":[{\"Value\": \"ACTIVE\",\"Comparison\":\"EQUALS\"}],\"AwsAccountId\":[{\"Value\": \"$ACCOUNT_NUM\",\"Comparison\":\"EQUALS\"}]}" - NEW_FINDING_IDS=$(echo -n "${SECURITYHUB_NEW_FINDINGS_IDS[@]}" | jq -cRs 'split(" ")') - SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --argjson ids "$NEW_FINDING_IDS" --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | select( .Id| first(select($ids[] == .)) // false | not) | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ]') + NEW_FINDING_FILE="$REGION_FOLDER/findings.json" + NEW_FINDING_IDS=$(echo -n "${SECURITYHUB_NEW_FINDINGS_IDS[@]}" | jq -cRs 'split(" ")' > $NEW_FINDING_FILE) + EXISTING_FILE="$REGION_FOLDER/existing.json" + EXISTING_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" > $EXISTING_FILE) + + SECURITY_HUB_PREVIOUS_FINDINGS=$(for id in $(comm -23 <(jq '[.Findings[].Id] | sort | .[]' $EXISTING_FILE) <(jq '[.[]] | sort | .[]' $NEW_FINDING_FILE)); + do + jq --arg updated_at $NEW_TIMESTAMP '.Findings[] | select(.Id == '"$id"') | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ' < $EXISTING_FILE + done | jq -s '.') + if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then FINDINGS_COUNT=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq '. | length') - for i in `seq 0 100 $FINDINGS_COUNT`; + for i in $(seq 0 50 $FINDINGS_COUNT); do - BATCH_FINDINGS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -c '.['"$i:$i+100"']') - BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${BATCH_FINDINGS}") - if [[ -z "${BATCH_IMPORT_RESULT}" ]] || jq -e '.FailedCount >= 1' <<< "${BATCH_IMPORT_RESULT}" > /dev/null 2>&1; then - echo -e "\n$RED ERROR!$NORMAL Failed to send check output to AWS Security Hub\n" + BATCH_FINDINGS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -c '.['"$i:$i+50"']') + BATCH_FINDINGS_COUNT=$(echo $BATCH_FINDINGS | jq '. | length') + if [ "$BATCH_FINDINGS_COUNT" -gt 0 ]; then + BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${BATCH_FINDINGS}") + if [[ -z "${BATCH_IMPORT_RESULT}" ]] || jq -e '.FailedCount >= 1' <<< "${BATCH_IMPORT_RESULT}" > /dev/null 2>&1; then + echo -e "\n$RED ERROR!$NORMAL Failed to send check output to AWS Security Hub\n" + fi fi done fi done - + rm -rf "$SH_TEMP_FOLDER" } sendToSecurityHub(){ diff --git a/prowler b/prowler index cae80272..ad6ab8f1 100755 --- a/prowler +++ b/prowler @@ -10,13 +10,7 @@ # Contact the author at https://blyx.com/contact # and open issues or ask questions at https://github.com/toniblyx/prowler - -# All CIS based checks in checks folder are licensed under a Creative Commons -# Attribution-NonCommercial-ShareAlike 4.0 International Public License. -# The link to the license terms can be found at -# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode -# -# Any other piece of code is licensed as Apache License 2.0 as specified in +# Code is licensed as Apache License 2.0 as specified in # each file. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 @@ -32,7 +26,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.6.1-15November2021 +PROWLER_VERSION=2.7.0-24January2022 PROWLER_DIR=$(dirname "$0") REGION="" @@ -67,57 +61,62 @@ usage(){ USAGE: `basename $0` [ -p -r -h ] Options: - -p specify your AWS profile to use (i.e.: default) - -r specify an AWS region to direct API requests to - (i.e.: us-east-1), all regions are checked anyway if the check requires it - -c specify one or multiple check ids separated by commas, to see all available checks use "-l" option + -p Specify your AWS profile to use. + (i.e.: default) + -r Specify an AWS region to direct API requests to. + (i.e.: us-east-1), all regions are checked anyway if the check requires it. + -c Specify one or multiple check ids separated by commas, to see all available checks use "-l" option. (i.e.: "check11" for check 1.1 or "extra71,extra72" for extra check 71 and extra check 72) -C Checklist file. See checklist.txt for reference and format. (i.e.: checklist.txt) - -g specify a group of checks by id, to see all available group of checks use "-L" + -g Specify a group of checks by id, to see all available group of checks use "-L". (i.e.: "group3" for entire section 3, "cislevel1" for CIS Level 1 Profile Definitions or "forensics-ready") - -f specify an AWS region to run checks against + -f Specify an AWS region to run checks against. (i.e.: us-west-1 or for multiple regions use single quote like 'us-west-1 us-west-2') - -m specify the maximum number of items to return for long-running requests (default: 100) - -M output mode: text (default), mono, html, json, json-asff, junit-xml, csv. They can be used combined comma separated. - (separator is ","; data is on stdout; progress on stderr). - -k keep the credential report - -n show check numbers to sort easier + -m Specify the maximum number of items to return for long-running requests (default: 100). + -M Output or report mode: text (default), mono, html, json, json-asff, junit-xml, csv. They can be used combined comma separated. + (i.e.: "html,json"; files created in background; progress on stdout) + -k Keep the credential report for debugging. + -n Show check numbers to sort easier. (i.e.: 1.01 instead of 1.1) - -l list all available checks only (does not perform any check). Add -g to only list checks within the specified group - -L list all groups (does not perform any check) - -e exclude group extras - -E execute all tests except a list of specified checks separated by comma (i.e. check21,check31) - -b do not print Prowler banner - -s show scoring report - -S send check output to AWS Security Hub - only valid when the output mode is json-asff (i.e. "-M json-asff -S") - -x specify external directory with custom checks (i.e. /my/own/checks, files must start by "check") - -q get only FAIL findings, will show WARNINGS when a resource is excluded - -A account id for the account where to assume a role, requires -R and -T + -l List all available checks only (does not perform any check). Add -g to only list checks within the specified group. + -L List all groups (does not perform any check). + -e Exclude group extras. + -E Execute all tests except a list of specified checks separated by comma. + (i.e. check21,check31) + -b Do not print Prowler banner. + -s Show scoring report (it is included by default in the html report). + -S Send check output to AWS Security Hub. Only valid when the output mode is json-asff + (i.e. "-M json-asff -S"). + -x Specify external directory with custom checks + (i.e. /my/own/checks, files must start by "check"). + -q Get only FAIL findings, will show WARNINGS when a resource is excluded. + -A Account id for the account where to assume a role, requires -R. (i.e.: 123456789012) - -R role name or role arn to assume in the account, requires -A and -T + -R Role name or role arn to assume in the account, requires -A. (i.e.: ProwlerRole) - -T session duration given to that role credentials in seconds, default 1h (3600) recommended 12h, requires -R and -T + -T Session duration given to that role credentials in seconds, default 1h (3600) recommended 12h, optional with -R and -A. (i.e.: 43200) - -I External ID to be used when assuming roles (not mandatory), requires -A and -R - -w whitelist file. See whitelist_sample.txt for reference and format + -I External ID to be used when assuming roles (not mandatory), requires -A and -R. + -w Whitelist file. See whitelist_sample.txt for reference and format. (i.e.: whitelist_sample.txt) -N Shodan API key used by check extra7102. - -o Custom output directory, if not specified will use default prowler/output, requires -M + -o Custom output directory, if not specified will use default prowler/output, requires -M . (i.e.: -M csv -o /tmp/reports/) -B Custom output bucket, requires -M and it can work also with -o flag. (i.e.: -M csv -B my-bucket or -M csv -B my-bucket/folder/) - -F Custom output report name, if not specified will use default output/prowler-output-ACCOUNT_NUM-OUTPUT_DATE - -z Failed Checks do not trigger exit code 3 + -D Same as -B but do not use the assumed role credentials to put objects to the bucket, instead uses the initial credentials. + -F Custom output report name, if not specified will use default output/prowler-output-ACCOUNT_NUM-OUTPUT_DATE.format. + -z Failed checks do not trigger exit code 3. -Z Specify one or multiple check ids separated by commas that will trigger exit code 3 if they fail. Unspecified checks will not trigger exit code 3. This will override "-z". - (i.e.: "-Z check11,check12" will cause check11 and/or check12 to trigger exit code 3 - -V show version number & exit - -h this help + (i.e.: "-Z check11,check12" will cause check11 and/or check12 to trigger exit code 3) + -V Show version number & exit. + -h This help. " exit } -while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:F:zZ:" OPTION; do +while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:D:F:zZ:" OPTION; do case $OPTION in h ) usage @@ -135,6 +134,7 @@ while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:F:zZ:" OPTION; do ;; p ) PROFILE=$OPTARG + AWS_PROFILE=$OPTARG ;; r ) REGION_OPT=$OPTARG @@ -210,6 +210,10 @@ while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:F:zZ:" OPTION; do B ) OUTPUT_BUCKET=$OPTARG ;; + D ) + OUTPUT_BUCKET=$OPTARG + OUTPUT_BUCKET_NOASSUME=1 + ;; F ) OUTPUT_FILE_NAME=$OPTARG ;; @@ -392,13 +396,16 @@ show_group_title() { # Function to execute the check execute_check() { - if [[ $ACCOUNT_TO_ASSUME ]]; then + if [[ -n "${ACCOUNT_TO_ASSUME}" || -n "${ROLE_TO_ASSUME}" ]]; then + # echo ******* I am here again to check on my role ******* # Following logic looks for time remaining in the session and review it # if it is less than 600 seconds, 10 minutes. CURRENT_TIMESTAMP=$(date -u "+%s") SESSION_TIME_REMAINING=$(expr $AWS_SESSION_EXPIRATION - $CURRENT_TIMESTAMP) - MINIMUM_REMAINING_TIME_ALLOWED="600" - if [[ $MINIMUM_REMAINING_TIME_ALLOWED > $SESSION_TIME_REMAINING ]]; then + # echo SESSION TIME REMAINING IN SECONDS: $SESSION_TIME_REMAINING + MINIMUM_REMAINING_TIME_ALLOWED=600 + if (( $MINIMUM_REMAINING_TIME_ALLOWED > $SESSION_TIME_REMAINING )); then + # echo LESS THAN 10 MIN LEFT: RE-ASSUMING... unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN @@ -497,7 +504,7 @@ execute_check() { fi else - textFail "ERROR! Use a valid check name (i.e. check41 or extra71)"; + textFail "Check ${CHECK_ID} does not exist. Use a valid check name (i.e. check41 or extra71)"; exit $EXITCODE fi fi @@ -565,7 +572,7 @@ show_all_titles() { fi done else - textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." + textFail "Group ${GROUP_ID_READ} does not exist. Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." show_all_group_titles exit $EXITCODE fi @@ -639,7 +646,8 @@ fi # Gather account data / test aws cli connectivity getWhoami -if [[ $ACCOUNT_TO_ASSUME ]]; then +if [[ -n "${ACCOUNT_TO_ASSUME}" || -n "${ROLE_TO_ASSUME}" ]]; then + backupInitialAWSCredentials assume_role fi @@ -656,10 +664,13 @@ if [[ $GROUP_ID_READ ]];then fi cleanTemp scoring + if [[ $OUTPUT_BUCKET_NOASSUME ]]; then + restoreInitialAWSCredentials + fi copyToS3 exit $EXITCODE else - textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." + textFail "Group ${GROUP_ID_READ} does not exist. Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." show_all_group_titles exit $EXITCODE fi @@ -684,6 +695,9 @@ if [[ $CHECK_ID ]];then if [[ "${MODES[@]}" =~ "html" ]]; then addHtmlFooter >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML fi + if [[ $OUTPUT_BUCKET_NOASSUME ]]; then + restoreInitialAWSCredentials + fi copyToS3 scoring cleanTemp @@ -698,13 +712,9 @@ fi scoring cleanTemp +if [[ $OUTPUT_BUCKET_NOASSUME ]]; then + restoreInitialAWSCredentials +fi copyToS3 -if [[ $ACCOUNT_TO_ASSUME ]]; then - # unset env variables with assumed role credentials - unset AWS_ACCESS_KEY_ID - unset AWS_SECRET_ACCESS_KEY - unset AWS_SESSION_TOKEN -fi - exit $EXITCODE diff --git a/util/Dockerfile b/util/Dockerfile index 9467cd0c..0bfd188c 100644 --- a/util/Dockerfile +++ b/util/Dockerfile @@ -1,13 +1,25 @@ -FROM alpine:3.13 +# Build command +# docker build --platform=linux/amd64 --no-cache -t prowler:latest -f util/Dockerfile . + +FROM public.ecr.aws/amazonlinux/amazonlinux:latest + +LABEL maintainer="https://github.com/toniblyx/prowler" ARG USERNAME=prowler ARG USERID=34000 -RUN addgroup -g ${USERID} ${USERNAME} && \ - adduser -s /bin/sh -G ${USERNAME} -D -u ${USERID} ${USERNAME} && \ - apk --update --no-cache add python3 bash curl jq file coreutils py3-pip git && \ - pip3 install --upgrade pip && \ - pip3 install awscli boto3 detect-secrets==1.0.3 +RUN yum install -y shadow-utils && \ + useradd -s /bin/sh -U -u ${USERID} ${USERNAME} && \ + yum install -y python3 bash curl jq coreutils py3-pip which unzip && \ + yum upgrade -y && \ + yum clean all && \ + pip3 install --upgrade pip && \ + pip3 install boto3 detect-secrets==1.0.3 && \ + pip3 cache purge && \ + curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip && \ + unzip awscliv2.zip && \ + aws/install && \ + rm -rf aws awscliv2.zip /var/cache/yum WORKDIR /prowler diff --git a/util/codebuild/codebuild-prowler-audit-account-cfn.yaml b/util/codebuild/codebuild-prowler-audit-account-cfn.yaml index 7cec6636..d417c078 100644 --- a/util/codebuild/codebuild-prowler-audit-account-cfn.yaml +++ b/util/codebuild/codebuild-prowler-audit-account-cfn.yaml @@ -184,15 +184,18 @@ Resources: Version: '2012-10-17' Statement: - Action: - - s3:GetAccountPublicAccessBlock - - glue:GetConnections - - glue:SearchTables - ds:ListAuthorizedApplications - ec2:GetEbsEncryptionByDefault - ecr:Describe* - support:Describe* - tag:GetTagKeys - lambda:GetFunction + - glue:GetConnections + - glue:GetSecurityConfiguration + - glue:SearchTables + - s3:GetAccountPublicAccessBlock + - shield:GetSubscriptionState + - shield:DescribeProtection Effect: Allow Resource: !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:catalog' - PolicyName: CodeBuild diff --git a/util/org-multi-account/ProwlerRole.yaml b/util/org-multi-account/ProwlerRole.yaml index 544cf1cd..183b2bee 100644 --- a/util/org-multi-account/ProwlerRole.yaml +++ b/util/org-multi-account/ProwlerRole.yaml @@ -96,6 +96,8 @@ Resources: - states:ListActivities - support:Describe* - tag:GetTagKeys + - shield:GetSubscriptionState + - shield:DescribeProtection - PolicyName: Prowler-S3-Reports PolicyDocument: Version: 2012-10-17 diff --git a/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml b/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml index d89c5452..bc7c0a2b 100644 --- a/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml +++ b/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml @@ -123,8 +123,12 @@ Resources: runtime-versions: python: 3.8 commands: - - echo "Updating yum..." + - echo "Updating yum ..." - yum -y update + - echo "Updating pip ..." + - python -m pip install --upgrade pip + - echo "Installing requirements ..." + - pip install "git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets" build: commands: - echo "Running Prowler with script" diff --git a/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml b/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml index 138d8809..5751f1f9 100644 --- a/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml +++ b/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml @@ -83,6 +83,7 @@ Resources: - dax:ListTables - ds:ListAuthorizedApplications - ds:DescribeRoles + - ec2:GetEbsEncryptionByDefault - ecr:Describe* - lambda:GetAccountSettings - lambda:GetFunctionConfiguration @@ -96,6 +97,8 @@ Resources: - states:ListActivities - support:Describe* - tag:GetTagKeys + - shield:GetSubscriptionState + - shield:DescribeProtection - PolicyName: Prowler-S3-Reports PolicyDocument: Version: 2012-10-17 diff --git a/util/terraform-kickstarter/main.tf b/util/terraform-kickstarter/main.tf index c51557b6..187b7723 100644 --- a/util/terraform-kickstarter/main.tf +++ b/util/terraform-kickstarter/main.tf @@ -311,15 +311,18 @@ resource "aws_iam_policy" "prowler_kickstarter_iam_policy" { }, { Action = [ - "s3:GetAccountPublicAccessBlock", - "glue:GetConnections", - "glue:SearchTables", "ds:ListAuthorizedApplications", "ec2:GetEbsEncryptionByDefault", "ecr:Describe*", "support:Describe*", "tag:GetTagKeys", - "lambda:GetFunction" + "lambda:GetFunction", + "glue:GetConnections", + "glue:GetSecurityConfiguration", + "glue:SearchTables", + "s3:GetAccountPublicAccessBlock", + "shield:GetSubscriptionState", + "shield:DescribeProtection" ] Effect = "Allow" Resource = "arn:aws:glue:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:catalog"