diff --git a/.gitignore b/.gitignore index 7644e14e..f6e46e88 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ Sessionx.vim *~ # Auto-generated tag files tags + # Persistent undo [._]*.un~ @@ -23,6 +24,9 @@ tags # Prowler output output/ +# Prowler found secrets +secrets-*/ + # JUnit Reports junit-reports/ diff --git a/LICENSE b/LICENSE index f764ae67..b9b7f40f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,2 @@ -All CIS based checks in the checks folder are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License. -The link to the license terms can be found at -https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode - -Any other piece of code is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at +Apache License 2.0 as specified in each file. You may obtain a copy of the License at LICENSE-APACHE-2.0 and http://www.apache.org/licenses/LICENSE-2.0 diff --git a/LICENSE-APACHE-2.0 b/LICENSE-APACHE-2.0 index cd482d89..46de5eb1 100644 --- a/LICENSE-APACHE-2.0 +++ b/LICENSE-APACHE-2.0 @@ -186,7 +186,7 @@ file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright [yyyy] [name of copyright owner] +Copyright 2021 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. diff --git a/LICENSE-CC-BY-SA-4.0 b/LICENSE-CC-BY-SA-4.0 deleted file mode 100644 index 63f44cc3..00000000 --- a/LICENSE-CC-BY-SA-4.0 +++ /dev/null @@ -1,360 +0,0 @@ -Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International -Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-NonCommercial-ShareAlike 4.0 International Public License -("Public License"). To the extent this Public License may be -interpreted as a contract, You are granted the Licensed Rights in -consideration of Your acceptance of these terms and conditions, and the -Licensor grants You such rights in consideration of benefits the -Licensor receives from making the Licensed Material available under -these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-NC-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution, NonCommercial, and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. NonCommercial means not primarily intended for or directed towards - commercial advantage or monetary compensation. For purposes of - this Public License, the exchange of the Licensed Material for - other material subject to Copyright and Similar Rights by digital - file-sharing or similar means is NonCommercial provided there is - no payment of monetary compensation in connection with the - exchange. - - l. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - m. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - n. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part, for NonCommercial purposes only; and - - b. produce, reproduce, and Share Adapted Material for - NonCommercial purposes only. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties, including when - the Licensed Material is used other than for NonCommercial - purposes. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-NC-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database for NonCommercial purposes - only; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. \ No newline at end of file diff --git a/README.md b/README.md index 43deffaf..727b7242 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,12 @@ Prowler has been written in bash using AWS-CLI and it works in Linux and OSX. Valid check numbers are based on the AWS CIS Benchmark guide, so 1.1 is check11 and 3.10 is check310 +### Regions + +By default Prowler scans all opt-in regions available, that might take a long execution time depending on the number of resources and regions used. Same applies for GovCloud or China regions. See below Advance usage for examples. + +Prowler has to parameters related to regions: `-r` that is used query AWS services API endpoints (it uses `us-east-1` by default and required for GovCloud or China) and the option `-f` that is to filter those regions you only want to scan. For example if you want to scan Dublin only use `-f eu-west-1` and if you want to scan Dublin and Ohio `-f 'eu-west-1 us-east-s'`, note the single quotes and space between regions. + ## Screenshots - Sample screenshot of report first lines: @@ -343,6 +349,9 @@ Sets the entropy limit for high entropy hex strings from environment variable `H export BASE64_LIMIT=4.5 export HEX_LIMIT=3.0 ``` +### Run Prowler using AWS CloudShell + +An easy way to run Prowler to scan your account is using AWS CloudShell. Read more and learn how to do it [here](util/cloudshell/README.md). ## Security Hub integration diff --git a/checks/check11 b/checks/check11 index d8040e41..6162db56 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check11="1.1" -CHECK_TITLE_check11="[check11] Avoid the use of the root account (Scored)" +CHECK_TITLE_check11="[check11] Avoid the use of the root account" CHECK_SCORED_check11="SCORED" CHECK_TYPE_check11="LEVEL1" CHECK_SEVERITY_check11="High" @@ -32,13 +35,13 @@ check11(){ days_not_in_use=$(how_many_days_from_today ${date%T*}) if [ "$days_not_in_use" -gt "$MAX_DAYS" ];then failures=1 - textFail "Root user in the account was last accessed ${MAX_DAYS#-} day ago" + textFail "$REGION: Root user in the account was last accessed ${MAX_DAYS#-} day ago" "$REGION" "root" break fi fi done if [[ $failures == 0 ]]; then - textPass "Root user in the account wasn't accessed in the last ${MAX_DAYS#-} days" + textPass "$REGION: Root user in the account wasn't accessed in the last ${MAX_DAYS#-} days" "$REGION" "root" fi } diff --git a/checks/check110 b/checks/check110 index 3e638cc5..2e60a65e 100644 --- a/checks/check110 +++ b/checks/check110 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check110="1.10" -CHECK_TITLE_check110="[check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" +CHECK_TITLE_check110="[check110] Ensure IAM password policy prevents password reuse: 24 or greater" CHECK_SCORED_check110="SCORED" CHECK_TYPE_check110="LEVEL1" CHECK_SEVERITY_check110="Medium" @@ -26,11 +29,11 @@ check110(){ COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) if [[ $COMMAND110 ]];then if [[ $COMMAND110 -gt "23" ]];then - textPass "Password Policy limits reuse" + textPass "$REGION: Password Policy limits reuse" "$REGION" "password policy" else - textFail "Password Policy has weak reuse requirement (lower than 24)" + textFail "$REGION: Password Policy has weak reuse requirement (lower than 24)" "$REGION" "password policy" fi else - textFail "Password Policy missing reuse requirement" + textFail "$REGION: Password Policy missing reuse requirement" "$REGION" "password policy" fi } diff --git a/checks/check111 b/checks/check111 index ea03f28b..1a696f0b 100644 --- a/checks/check111 +++ b/checks/check111 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check111="1.11" -CHECK_TITLE_check111="[check111] Ensure IAM password policy expires passwords within 90 days or less (Scored)" +CHECK_TITLE_check111="[check111] Ensure IAM password policy expires passwords within 90 days or less" CHECK_SCORED_check111="SCORED" CHECK_TYPE_check111="LEVEL1" CHECK_SEVERITY_check111="Medium" @@ -26,11 +29,11 @@ check111(){ COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query PasswordPolicy.MaxPasswordAge --output text 2> /dev/null) if [[ $COMMAND111 == [0-9]* ]];then if [[ "$COMMAND111" -le "90" ]];then - textPass "Password Policy includes expiration (Value: $COMMAND111)" + textPass "$REGION: Password Policy includes expiration (Value: $COMMAND111)" "$REGION" "password policy" else - textFail "Password expiration is set greater than 90 days" + textFail "$REGION: Password expiration is set greater than 90 days" "$REGION" "password policy" fi else - textFail "Password expiration is not set" + textFail "$REGION: Password expiration is not set" "$REGION" "password policy" fi } diff --git a/checks/check112 b/checks/check112 index 4431bf29..f2f6c422 100644 --- a/checks/check112 +++ b/checks/check112 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check112="1.12" -CHECK_TITLE_check112="[check112] Ensure no root account access key exists (Scored)" +CHECK_TITLE_check112="[check112] Ensure no root account access key exists" CHECK_SCORED_check112="SCORED" CHECK_TYPE_check112="LEVEL1" CHECK_SEVERITY_check112="Critical" @@ -27,13 +30,13 @@ check112(){ ROOTKEY1=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $9 }') ROOTKEY2=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $14 }') if [ "$ROOTKEY1" == "false" ];then - textPass "No access key 1 found for root" + textPass "$REGION: No access key 1 found for root" "$REGION" "root access key1" else - textFail "Found access key 1 for root" + textFail "$REGION: Found access key 1 for root" "$REGION" "root access key1" fi if [ "$ROOTKEY2" == "false" ];then - textPass "No access key 2 found for root" + textPass "$REGION: No access key 2 found for root" "$REGION" "root access key2" else - textFail "Found access key 2 for root" + textFail "$REGION: Found access key 2 for root" "$REGION" "root access key2" fi } diff --git a/checks/check113 b/checks/check113 index a5414034..657c9b0a 100644 --- a/checks/check113 +++ b/checks/check113 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check113="1.13" -CHECK_TITLE_check113="[check113] Ensure MFA is enabled for the root account (Scored)" +CHECK_TITLE_check113="[check113] Ensure MFA is enabled for the root account" CHECK_SCORED_check113="SCORED" CHECK_TYPE_check113="LEVEL1" CHECK_SEVERITY_check113="Critical" @@ -25,8 +28,8 @@ check113(){ # "Ensure MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') if [ "$COMMAND113" == "1" ]; then - textPass "Virtual MFA is enabled for root" + textPass "$REGION: Virtual MFA is enabled for root" "$REGION" "MFA" else - textFail "MFA is not ENABLED for root account" + textFail "$REGION: MFA is not ENABLED for root account" "$REGION" "MFA" fi } diff --git a/checks/check114 b/checks/check114 index 3b489350..7872583f 100644 --- a/checks/check114 +++ b/checks/check114 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check114="1.14" -CHECK_TITLE_check114="[check114] Ensure hardware MFA is enabled for the root account (Scored)" +CHECK_TITLE_check114="[check114] Ensure hardware MFA is enabled for the root account" CHECK_SCORED_check114="SCORED" CHECK_TYPE_check114="LEVEL2" CHECK_SEVERITY_check114="Critical" @@ -27,11 +30,11 @@ check114(){ if [ "$COMMAND113" == "1" ]; then COMMAND114=$($AWSCLI iam list-virtual-mfa-devices $PROFILE_OPT --region $REGION --output text --assignment-status Assigned --query 'VirtualMFADevices[*].[SerialNumber]' | grep "^arn:${AWS_PARTITION}:iam::[0-9]\{12\}:mfa/root-account-mfa-device$") if [[ "$COMMAND114" ]]; then - textFail "Only Virtual MFA is enabled for root" + textFail "$REGION: Only Virtual MFA is enabled for root" "$REGION" "MFA" else - textPass "Hardware MFA is enabled for root" + textPass "$REGION: Hardware MFA is enabled for root" "$REGION" "MFA" fi else - textFail "MFA is not ENABLED for root account" + textFail "$REGION: MFA is not ENABLED for root account" "$REGION" "MFA" fi } diff --git a/checks/check115 b/checks/check115 index 57827b00..356ba6d7 100644 --- a/checks/check115 +++ b/checks/check115 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check115="1.15" -CHECK_TITLE_check115="[check115] Ensure security questions are registered in the AWS account (Not Scored)" +CHECK_TITLE_check115="[check115] Ensure security questions are registered in the AWS account" CHECK_SCORED_check115="NOT_SCORED" CHECK_TYPE_check115="LEVEL1" CHECK_SEVERITY_check115="Medium" @@ -23,7 +26,5 @@ CHECK_CAF_EPIC_check115='IAM' check115(){ # "Ensure security questions are registered in the AWS account (Not Scored)" - textInfo "No command available for check 1.15 " - textInfo "Login to the AWS Console as root & click on the Account " - textInfo "Name -> My Account -> Configure Security Challenge Questions " + textInfo "No command available for check 1.15. Login to the AWS Console as root & click on the Account. Name -> My Account -> Configure Security Challenge Questions." } diff --git a/checks/check116 b/checks/check116 index 3edd41c9..18a0cbc3 100644 --- a/checks/check116 +++ b/checks/check116 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check116="1.16" -CHECK_TITLE_check116="[check116] Ensure IAM policies are attached only to groups or roles (Scored)" +CHECK_TITLE_check116="[check116] Ensure IAM policies are attached only to groups or roles" CHECK_SCORED_check116="SCORED" CHECK_TYPE_check116="LEVEL1" CHECK_SEVERITY_check116="Low" @@ -30,16 +33,16 @@ check116(){ for user in $LIST_USERS;do USER_POLICY=$($AWSCLI iam list-attached-user-policies --output text $PROFILE_OPT --region $REGION --user-name $user) if [[ $USER_POLICY ]]; then - textFail "$user has managed policy directly attached" + textFail "$REGION: $user has managed policy directly attached" "$REGION" "$user" C116_NUM_USERS=$(expr $C116_NUM_USERS + 1) fi USER_POLICY=$($AWSCLI iam list-user-policies --output text $PROFILE_OPT --region $REGION --user-name $user) if [[ $USER_POLICY ]]; then - textFail "$user has inline policy directly attached" + textFail "$REGION: $user has inline policy directly attached" "$REGION" "$user" C116_NUM_USERS=$(expr $C116_NUM_USERS + 1) fi done if [[ $C116_NUM_USERS -eq 0 ]]; then - textPass "No policies attached to users" + textPass "$REGION: No policies attached to users" "$REGION" "$user" fi } diff --git a/checks/check117 b/checks/check117 index e390ad47..e9854cd0 100644 --- a/checks/check117 +++ b/checks/check117 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check117="1.17" -CHECK_TITLE_check117="[check117] Maintain current contact details (Not Scored)" +CHECK_TITLE_check117="[check117] Maintain current contact details" CHECK_SCORED_check117="NOT_SCORED" CHECK_TYPE_check117="LEVEL1" CHECK_SEVERITY_check117="Medium" @@ -24,6 +27,5 @@ CHECK_CAF_EPIC_check117='IAM' check117(){ # "Maintain current contact details (Scored)" # No command available - textInfo "No command available for check 1.17 " - textInfo "See section 1.17 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.17. See section 1.17 on the CIS Benchmark guide for details." } diff --git a/checks/check118 b/checks/check118 index ef69a226..736bb594 100644 --- a/checks/check118 +++ b/checks/check118 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check118="1.18" -CHECK_TITLE_check118="[check118] Ensure security contact information is registered (Not Scored)" +CHECK_TITLE_check118="[check118] Ensure security contact information is registered" CHECK_SCORED_check118="NOT_SCORED" CHECK_TYPE_check118="LEVEL1" CHECK_SEVERITY_check118="Medium" @@ -24,6 +27,5 @@ CHECK_CAF_EPIC_check118='IAM' check118(){ # "Ensure security contact information is registered (Scored)" # No command available - textInfo "No command available for check 1.18 " - textInfo "See section 1.18 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.18. See section 1.18 on the CIS Benchmark guide for details." } diff --git a/checks/check119 b/checks/check119 index 43db9e77..e9d148dc 100644 --- a/checks/check119 +++ b/checks/check119 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check119="1.19" -CHECK_TITLE_check119="[check119] Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" +CHECK_TITLE_check119="[check119] Ensure IAM instance roles are used for AWS resource access from instances" CHECK_SCORED_check119="NOT_SCORED" CHECK_TYPE_check119="LEVEL2" CHECK_SEVERITY_check119="Medium" @@ -33,14 +36,14 @@ check119(){ if [[ $STATE_NAME != "terminated" && $STATE_NAME != "shutting-down" ]]; then PROFILEARN=$(echo $EC2_DATA | jq -r --arg i "$instance" 'select(.InstanceId==$i)|.ProfileArn') if [[ $PROFILEARN == "null" ]]; then - textFail "$regx: Instance $instance not associated with an instance role" $regx + textFail "$regx: Instance $instance not associated with an instance role" "$regx" "$instance" else - textPass "$regx: Instance $instance associated with role ${PROFILEARN##*/}" $regx + textPass "$regx: Instance $instance associated with role ${PROFILEARN##*/}" "$regx" "$instance" fi fi done else - textInfo "$regx: No EC2 instances found" $regx + textInfo "$regx: No EC2 instances found" "$regx" "$instance" fi done } diff --git a/checks/check12 b/checks/check12 index 1d8f572f..deca5af2 100644 --- a/checks/check12 +++ b/checks/check12 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check12="1.2" -CHECK_TITLE_check12="[check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" +CHECK_TITLE_check12="[check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password" CHECK_SCORED_check12="SCORED" CHECK_TYPE_check12="LEVEL1" CHECK_SEVERITY_check12="High" @@ -19,7 +22,7 @@ CHECK_ALTERNATE_check102="check12" CHECK_ASFF_COMPLIANCE_TYPE_check12="ens-op.acc.5.aws.iam.1" CHECK_SERVICENAME_check12="iam" CHECK_RISK_check12='Unauthorized access to this critical account if password is not secure or it is disclosed in any way.' -CHECK_REMEDIATION_check12='Enable MFA for root account. is a simple best practice that adds an extra layer of protection on top of your user name and password. Recommended to use hardware keys over virtual MFA.' +CHECK_REMEDIATION_check12='Enable MFA for root account. MFA is a simple best practice that adds an extra layer of protection on top of your user name and password. Recommended to use hardware keys over virtual MFA.' CHECK_DOC_check12='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_enable_virtual.html' CHECK_CAF_EPIC_check12='IAM' @@ -33,9 +36,9 @@ check12(){ done) if [[ $COMMAND12 ]]; then for u in $COMMAND12; do - textFail "User $u has Password enabled but MFA disabled" + textFail "$REGION: User $u has Password enabled but MFA disabled" "$REGION" "$u" done else - textPass "No users found with Password enabled and MFA disabled" + textPass "$REGION: No users found with Password enabled and MFA disabled" "$REGION" "$u" fi } diff --git a/checks/check120 b/checks/check120 index 6a520b16..e2935a5b 100644 --- a/checks/check120 +++ b/checks/check120 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check120="1.20" -CHECK_TITLE_check120="[check120] Ensure a support role has been created to manage incidents with AWS Support (Scored)" +CHECK_TITLE_check120="[check120] Ensure a support role has been created to manage incidents with AWS Support" CHECK_SCORED_check120="SCORED" CHECK_TYPE_check120="LEVEL1" CHECK_SEVERITY_check120="Medium" @@ -31,16 +34,16 @@ check120(){ POLICYROLES=$($AWSCLI iam list-entities-for-policy --policy-arn $SUPPORTPOLICYARN $PROFILE_OPT --region $REGION --output text | awk -F$'\t' '{ print $3 }') if [[ $POLICYROLES ]];then for name in $POLICYROLES; do - textPass "Support Policy attached to $name" + textPass "$REGION: Support Policy attached to $name" "$REGION" "$name" done # for user in $(echo "$POLICYUSERS" | grep UserName | cut -d'"' -f4) ; do # textInfo "User $user has support access via $policyarn" # done else - textFail "Support Policy not applied to any Role" + textFail "$REGION: Support Policy not applied to any Role" "$REGION" "$name" fi done else - textFail "No Support Policy found" + textFail "$REGION: No Support Policy found" "$REGION" "$name" fi } diff --git a/checks/check121 b/checks/check121 index df966919..64dd729c 100644 --- a/checks/check121 +++ b/checks/check121 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check121="1.21" -CHECK_TITLE_check121="[check121] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" +CHECK_TITLE_check121="[check121] Do not setup access keys during initial user setup for all IAM users that have a console password" CHECK_SCORED_check121="NOT_SCORED" CHECK_TYPE_check121="LEVEL1" CHECK_SEVERITY_check121="Medium" @@ -32,10 +35,10 @@ check121(){ LIST_USERS_KEY1_ACTIVE=$(for user in $LIST_USERS_KEY1_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$4,$9 }'|grep "true true$"|awk '{ print $1 }'|sed 's/[[:blank:]]+/,/g' ; done) if [[ $LIST_USERS_KEY1_ACTIVE ]]; then for user in $LIST_USERS_KEY1_ACTIVE; do - textFail "User $user has never used access key 1" + textFail "$REGION: User $user has never used access key 1" "$REGION" "$user" done else - textPass "No users found with access key 1 never used" + textPass "$REGION: No users found with access key 1 never used" "$REGION" "$user" fi # List of USERS with KEY2 last_used_date as N/A LIST_USERS_KEY2_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$16 }'|grep N/A |awk '{ print $1 }' ; done) @@ -43,9 +46,9 @@ check121(){ LIST_USERS_KEY2_ACTIVE=$(for user in $LIST_USERS_KEY2_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$4,$14 }'|grep "true true$" |awk '{ print $1 }' ; done) if [[ $LIST_USERS_KEY2_ACTIVE ]]; then for user in $LIST_USERS_KEY2_ACTIVE; do - textFail "User $user has never used access key 2" + textFail "$REGION: User $user has never used access key 2" "$REGION" "$user" done else - textPass "No users found with access key 2 never used" + textPass "$REGION: No users found with access key 2 never used" "$REGION" "$user" fi } diff --git a/checks/check122 b/checks/check122 index 29b69ffe..70423199 100644 --- a/checks/check122 +++ b/checks/check122 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check122="1.22" -CHECK_TITLE_check122="[check122] Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" +CHECK_TITLE_check122="[check122] Ensure IAM policies that allow full \"*:*\" administrative privileges are not created" CHECK_SCORED_check122="SCORED" CHECK_TYPE_check122="LEVEL1" CHECK_SEVERITY_check122="Medium" @@ -26,7 +29,6 @@ check122(){ # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION --scope Local --query 'Policies[*].[Arn,DefaultVersionId]' | grep -v -e '^None$' | awk -F '\t' '{print $1","$2"\n"}') if [[ $LIST_CUSTOM_POLICIES ]]; then - textInfo "Looking for custom policies: (skipping default policies - it may take few seconds...)" for policy in $LIST_CUSTOM_POLICIES; do POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}') POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}') @@ -36,14 +38,13 @@ check122(){ fi done if [[ $POLICIES_ALLOW_LIST ]]; then - textInfo "List of custom policies: " for policy in $POLICIES_ALLOW_LIST; do - textFail "Policy $policy allows \"*:*\"" + textFail "$REGION: Policy $policy allows \"*:*\"" "$REGION" "$policy" done else - textPass "No custom policy found that allow full \"*:*\" administrative privileges" + textPass "$REGION: No custom policy found that allow full \"*:*\" administrative privileges" "$REGION" "$policy" fi else - textPass "No custom policies found" + textPass "$REGION: No custom policies found" "$REGION" "$policy" fi } diff --git a/checks/check13 b/checks/check13 index 80388de1..81b2c52b 100644 --- a/checks/check13 +++ b/checks/check13 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check13="1.3" -CHECK_TITLE_check13="[check13] Ensure credentials unused for 90 days or greater are disabled (Scored)" +CHECK_TITLE_check13="[check13] Ensure credentials unused for 90 days or greater are disabled" CHECK_SCORED_check13="SCORED" CHECK_TYPE_check13="LEVEL1" CHECK_SEVERITY_check13="Medium" diff --git a/checks/check14 b/checks/check14 index 01147aca..0d9d1cc7 100644 --- a/checks/check14 +++ b/checks/check14 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check14="1.4" -CHECK_TITLE_check14="[check14] Ensure access keys are rotated every 90 days or less (Scored)" +CHECK_TITLE_check14="[check14] Ensure access keys are rotated every 90 days or less" CHECK_SCORED_check14="SCORED" CHECK_TYPE_check14="LEVEL1" CHECK_SEVERITY_check14="Medium" @@ -37,15 +40,15 @@ check14(){ HOWOLDER=$(how_older_from_today $DATEROTATED1) if [ $HOWOLDER -gt "90" ];then - textFail "$user has not rotated access key 1 in over 90 days" + textFail "$REGION: $user has not rotated access key 1 in over 90 days" "$REGION" "$user" C14_NUM_USERS1=$(expr $C14_NUM_USERS1 + 1) fi done if [[ $C14_NUM_USERS1 -eq 0 ]]; then - textPass "No users with access key 1 older than 90 days" + textPass "$REGION: No users with access key 1 older than 90 days" "$REGION" "$user" fi else - textPass "No users with access key 1" + textPass "$REGION: No users with access key 1" "$REGION" "$user" fi if [[ $LIST_OF_USERS_WITH_ACCESS_KEY2 ]]; then @@ -55,14 +58,14 @@ check14(){ DATEROTATED2=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $15 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') HOWOLDER=$(how_older_from_today $DATEROTATED2) if [ $HOWOLDER -gt "90" ];then - textFail "$user has not rotated access key 2 in over 90 days" + textFail "$REGION: $user has not rotated access key 2 in over 90 days" "$REGION" "$user" C14_NUM_USERS2=$(expr $C14_NUM_USERS2 + 1) fi done if [[ $C14_NUM_USERS2 -eq 0 ]]; then - textPass "No users with access key 2 older than 90 days" + textPass "$REGION: No users with access key 2 older than 90 days" "$REGION" "$user" fi else - textPass "No users with access key 2" + textPass "$REGION: No users with access key 2" "$REGION" "$user" fi } diff --git a/checks/check15 b/checks/check15 index 4cbc6203..079245d0 100644 --- a/checks/check15 +++ b/checks/check15 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check15="1.5" -CHECK_TITLE_check15="[check15] Ensure IAM password policy requires at least one uppercase letter (Scored)" +CHECK_TITLE_check15="[check15] Ensure IAM password policy requires at least one uppercase letter" CHECK_SCORED_check15="SCORED" CHECK_TYPE_check15="LEVEL1" CHECK_SEVERITY_check15="Medium" @@ -25,8 +28,8 @@ check15(){ # "Ensure IAM password policy requires at least one uppercase letter (Scored)" COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true if [[ "$COMMAND15" == "true" ]];then - textPass "Password Policy requires upper case" + textPass "$REGION: Password Policy requires upper case" "$REGION" "password policy" else - textFail "Password Policy missing upper-case requirement" + textFail "$REGION: Password Policy missing upper-case requirement" "$REGION" "password policy" fi } diff --git a/checks/check16 b/checks/check16 index 009a3cd3..719811d9 100644 --- a/checks/check16 +++ b/checks/check16 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check16="1.6" -CHECK_TITLE_check16="[check16] Ensure IAM password policy require at least one lowercase letter (Scored)" +CHECK_TITLE_check16="[check16] Ensure IAM password policy require at least one lowercase letter" CHECK_SCORED_check16="SCORED" CHECK_TYPE_check16="LEVEL1" CHECK_SEVERITY_check16="Medium" @@ -25,8 +28,8 @@ check16(){ # "Ensure IAM password policy require at least one lowercase letter (Scored)" COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true if [[ "$COMMAND16" == "true" ]];then - textPass "Password Policy requires lower case" + textPass "$REGION: Password Policy requires lower case" "$REGION" "password policy" else - textFail "Password Policy missing lower-case requirement" + textFail "$REGION: Password Policy missing lower-case requirement" "$REGION" "password policy" fi } diff --git a/checks/check17 b/checks/check17 index 5230095f..72fdd247 100644 --- a/checks/check17 +++ b/checks/check17 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check17="1.7" -CHECK_TITLE_check17="[check17] Ensure IAM password policy require at least one symbol (Scored)" +CHECK_TITLE_check17="[check17] Ensure IAM password policy require at least one symbol" CHECK_SCORED_check17="SCORED" CHECK_TYPE_check17="LEVEL1" CHECK_SEVERITY_check17="Medium" @@ -25,8 +28,8 @@ check17(){ # "Ensure IAM password policy require at least one symbol (Scored)" COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true if [[ "$COMMAND17" == "true" ]];then - textPass "Password Policy requires symbol" + textPass "$REGION: Password Policy requires symbol" "$REGION" "password policy" else - textFail "Password Policy missing symbol requirement" + textFail "$REGION: Password Policy missing symbol requirement" "$REGION" "password policy" fi } diff --git a/checks/check18 b/checks/check18 index 453a0a7d..c13e101b 100644 --- a/checks/check18 +++ b/checks/check18 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check18="1.8" -CHECK_TITLE_check18="[check18] Ensure IAM password policy require at least one number (Scored)" +CHECK_TITLE_check18="[check18] Ensure IAM password policy require at least one number" CHECK_SCORED_check18="SCORED" CHECK_TYPE_check18="LEVEL1" CHECK_SEVERITY_check18="Medium" @@ -25,8 +28,8 @@ check18(){ # "Ensure IAM password policy require at least one number (Scored)" COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true if [[ "$COMMAND18" == "true" ]];then - textPass "Password Policy requires number" + textPass "$REGION: Password Policy requires number" "$REGION" "password policy" else - textFail "Password Policy missing number requirement" + textFail "$REGION: Password Policy missing number requirement" "$REGION" "password policy" fi } diff --git a/checks/check19 b/checks/check19 index 97b43848..e8b92818 100644 --- a/checks/check19 +++ b/checks/check19 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check19="1.9" -CHECK_TITLE_check19="[check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored)" +CHECK_TITLE_check19="[check19] Ensure IAM password policy requires minimum length of 14 or greater" CHECK_SCORED_check19="SCORED" CHECK_TYPE_check19="LEVEL1" CHECK_SEVERITY_check19="Medium" @@ -25,8 +28,8 @@ check19(){ # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) if [[ $COMMAND19 -gt "13" ]];then - textPass "Password Policy requires more than 13 characters" + textPass "$REGION: Password Policy requires more than 13 characters" "$REGION" "password policy" else - textFail "Password Policy missing or weak length requirement" + textFail "$REGION: Password Policy missing or weak length requirement" "$REGION" "password policy" fi } diff --git a/checks/check21 b/checks/check21 index b9e63b97..0446243e 100644 --- a/checks/check21 +++ b/checks/check21 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check21="2.1" -CHECK_TITLE_check21="[check21] Ensure CloudTrail is enabled in all regions (Scored)" +CHECK_TITLE_check21="[check21] Ensure CloudTrail is enabled in all regions" CHECK_SCORED_check21="SCORED" CHECK_TYPE_check21="LEVEL1" CHECK_SEVERITY_check21="High" @@ -29,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -43,15 +46,20 @@ check21(){ MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail) if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then - textFail "Trail $trail in $regx is not enabled for all regions" + textFail "$regx: Trail $trail is not enabled for all regions" "$regx" "$trail" else - textPass "Trail $trail in $regx is enabled for all regions" + TRAIL_ON_OFF_STATUS=$($AWSCLI cloudtrail get-trail-status $PROFILE_OPT --region $TRAIL_REGION --name $trail --query IsLogging --output text) + if [[ "$TRAIL_ON_OFF_STATUS" == 'False' ]];then + textFail "$regx: Trail $trail is configured for all regions but it is OFF" "$regx" "$trail" + else + textPass "$regx: Trail $trail is enabled for all regions" "$regx" "$trail" + fi fi done fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$regx: No CloudTrail trails were found in the account" "$regx" "$trail" fi } diff --git a/checks/check22 b/checks/check22 index 94fbe2f5..3ae3e775 100644 --- a/checks/check22 +++ b/checks/check22 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check22="2.2" -CHECK_TITLE_check22="[check22] Ensure CloudTrail log file validation is enabled (Scored)" +CHECK_TITLE_check22="[check22] Ensure CloudTrail log file validation is enabled" CHECK_SCORED_check22="SCORED" CHECK_TYPE_check22="LEVEL2" CHECK_SEVERITY_check22="Medium" @@ -29,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -43,15 +46,15 @@ check22(){ LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail) if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then - textFail "Trail $trail in $regx log file validation disabled" + textFail "$regx: Trail $trail log file validation disabled" "$regx" "$trail" else - textPass "Trail $trail in $regx log file validation enabled" + textPass "$regx: Trail $trail log file validation enabled" "$regx" "$trail" fi done fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" fi } diff --git a/checks/check23 b/checks/check23 index d88cc079..56984176 100644 --- a/checks/check23 +++ b/checks/check23 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check23="2.3" -CHECK_TITLE_check23="[check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" +CHECK_TITLE_check23="[check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible" CHECK_SCORED_check23="SCORED" CHECK_TYPE_check23="LEVEL1" CHECK_SEVERITY_check23="Critical" @@ -29,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -86,6 +89,6 @@ check23(){ fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" fi } diff --git a/checks/check24 b/checks/check24 index c423e64c..57691f3b 100644 --- a/checks/check24 +++ b/checks/check24 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check24="2.4" -CHECK_TITLE_check24="[check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" +CHECK_TITLE_check24="[check24] Ensure CloudTrail trails are integrated with CloudWatch Logs" CHECK_SCORED_check24="SCORED" CHECK_TYPE_check24="LEVEL1" CHECK_SEVERITY_check24="Low" @@ -29,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -43,14 +46,14 @@ check24(){ LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail $PROFILE_OPT --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then - textFail "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + textFail "$TRAIL_REGION: $trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" "$TRAIL_REGION" "$trail" else LATESTDELIVERY_DATE=$(timestamp_to_date $LATESTDELIVERY_TIMESTAMP) HOWOLDER=$(how_older_from_today $LATESTDELIVERY_DATE) if [ $HOWOLDER -gt "1" ];then - textFail "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + textFail "$TRAIL_REGION: $trail trail is not logging in the last 24h or not configured" "$TRAIL_REGION" "$trail" else - textPass "$trail trail has been logging during the last 24h (it is in $TRAIL_REGION)" + textPass "$TRAIL_REGION: $trail trail has been logging during the last 24h" "$TRAIL_REGION" "$trail" fi fi @@ -58,6 +61,6 @@ check24(){ fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" fi } diff --git a/checks/check25 b/checks/check25 index d836e7c9..c853cde5 100644 --- a/checks/check25 +++ b/checks/check25 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check25="2.5" -CHECK_TITLE_check25="[check25] Ensure AWS Config is enabled in all regions (Scored)" +CHECK_TITLE_check25="[check25] Ensure AWS Config is enabled in all regions" CHECK_SCORED_check25="SCORED" CHECK_TYPE_check25="LEVEL1" CHECK_SEVERITY_check25="Medium" @@ -28,17 +31,17 @@ 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 "Access Denied trying to describe configuration recorder status in $regx" + textFail "$regx: Access Denied trying to describe configuration recorder status" "$regx" "recorder" continue fi if [[ $CHECK_AWSCONFIG_RECORDING == "True" ]]; then if [[ $CHECK_AWSCONFIG_STATUS == "SUCCESS" ]]; then - textPass "Region $regx AWS Config recorder enabled" + textPass "$regx: AWS Config recorder enabled" "$regx" "recorder" else - textFail "Region $regx AWS Config recorder in failure state" + textFail "$regx: AWS Config recorder in failure state" "$regx" "recorder" fi else - textFail "Region $regx AWS Config recorder disabled" + textFail "$regx: AWS Config recorder disabled" "$regx" "recorder" fi done } diff --git a/checks/check26 b/checks/check26 index 7730623e..a6663a22 100644 --- a/checks/check26 +++ b/checks/check26 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check26="2.6" -CHECK_TITLE_check26="[check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" +CHECK_TITLE_check26="[check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket" CHECK_SCORED_check26="SCORED" CHECK_TYPE_check26="LEVEL1" CHECK_SEVERITY_check26="Medium" @@ -28,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -42,13 +45,13 @@ check26(){ CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].[S3BucketName]' --output text --trail-name-list $trail) if [[ -z $CLOUDTRAILBUCKET ]]; then - textFail "Trail $trail in $TRAIL_REGION does not publish to S3" + textFail "$regx: Trail $trail does not publish to S3" "$TRAIL_REGION" "$trail" continue fi CLOUDTRAIL_ACCOUNT_ID=$(echo $trail | awk -F: '{ print $5 }') if [ "$CLOUDTRAIL_ACCOUNT_ID" != "$ACCOUNT_NUM" ]; then - textInfo "Trail $trail in $TRAIL_REGION S3 logging bucket $CLOUDTRAILBUCKET is not in current account" + textInfo "$regx: Trail $trail S3 logging bucket $CLOUDTRAILBUCKET is not in current account" "$TRAIL_REGION" "$trail" continue fi @@ -59,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 "Trail $trail in $TRAIL_REGION Access Denied getting bucket location for $CLOUDTRAILBUCKET" + textFail "$regx: Trail $trail Access Denied getting bucket location for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -71,20 +74,20 @@ check26(){ CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $CLOUDTRAILBUCKET $PROFILE_OPT --region $BUCKET_LOCATION --query 'LoggingEnabled.TargetBucket' --output text 2>&1) if [[ $(echo "$CLOUDTRAILBUCKET_LOGENABLED" | grep AccessDenied) ]]; then - textInfo "Trail $trail in $TRAIL_REGION Access Denied getting bucket logging for $CLOUDTRAILBUCKET" + textInfo "$regx: Trail $trail Access Denied getting bucket logging for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" continue fi if [[ $CLOUDTRAILBUCKET_LOGENABLED != "None" ]]; then - textPass "Trail $trail in $TRAIL_REGION S3 bucket access logging is enabled for $CLOUDTRAILBUCKET" + textPass "$regx: Trail $trail S3 bucket access logging is enabled for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" else - textFail "Trail $trail in $TRAIL_REGION S3 bucket access logging is not enabled for $CLOUDTRAILBUCKET" + textFail "$regx: Trail $trail S3 bucket access logging is not enabled for $CLOUDTRAILBUCKET" "$TRAIL_REGION" "$trail" fi done fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" fi } diff --git a/checks/check27 b/checks/check27 index 1afea54d..fa6a432d 100644 --- a/checks/check27 +++ b/checks/check27 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check27="2.7" -CHECK_TITLE_check27="[check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" +CHECK_TITLE_check27="[check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs" CHECK_SCORED_check27="SCORED" CHECK_TYPE_check27="LEVEL2" CHECK_SEVERITY_check27="Medium" @@ -29,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 "Access Denied trying to describe trails in $regx" + textFail "$regx: Access Denied trying to describe trails" "$regx" "$trail" continue fi if [[ $TRAILS_AND_REGIONS ]]; then @@ -43,14 +46,14 @@ check27(){ KMSKEYID=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $TRAIL_REGION --query 'trailList[*].KmsKeyId' --output text --trail-name-list $trail) if [[ "$KMSKEYID" ]];then - textPass "Trail $trail in $regx has encryption enabled" + textPass "$regx: Trail $trail has encryption enabled" "$regx" "$trail" else - textFail "Trail $trail in $regx has encryption disabled" + textFail "$regx: Trail $trail has encryption disabled" "$regx" "$trail" fi done fi done if [[ $trail_count == 0 ]]; then - textFail "No CloudTrail trails were found in the account" + textFail "$REGION: No CloudTrail trails were found in the account" "$REGION" "$trail" fi } diff --git a/checks/check28 b/checks/check28 index b35b4c95..aef746b1 100644 --- a/checks/check28 +++ b/checks/check28 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check28="2.8" -CHECK_TITLE_check28="[check28] Ensure rotation for customer created KMS CMKs is enabled (Scored)" +CHECK_TITLE_check28="[check28] Ensure rotation for customer created KMS CMKs is enabled" CHECK_SCORED_check28="SCORED" CHECK_TYPE_check28="LEVEL2" CHECK_SEVERITY_check28="Medium" @@ -27,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 "Access Denied trying to list keys in $regx" + textFail "$regx: Access Denied trying to list keys" "$regx" "$key" continue fi if [[ $CHECK_KMS_KEYLIST ]]; then @@ -35,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" + textFail "$regx: Key $key Access Denied describing key" "$regx" "$key" continue fi @@ -53,25 +56,25 @@ check28(){ cmk_count=$((cmk_count + 1)) if [[ "$KEYORIGIN" == "EXTERNAL" ]]; then - textPass "$regx: Key $key uses imported key material" + textPass "$regx: Key $key uses imported key material" "$regx" "$key" 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" + textFail "$regx: Key $key Access Denied getting key rotation status" "$regx" "$key" continue fi if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then - textPass "$regx: Key $key automatic rotation of the key material is enabled" + textPass "$regx: Key $key automatic rotation of the key material is enabled" "$regx" "$key" else - textFail "$regx: Key $key automatic rotation of the key material is disabled" + textFail "$regx: Key $key automatic rotation of the key material is disabled" "$regx" "$key" fi fi done if [[ $cmk_count == 0 ]]; then - textInfo "$regx: This region has no customer managed keys" + textInfo "$regx: This region has no customer managed keys" "$regx" "$key" fi else - textInfo "$regx: This region has no KMS keys" + textInfo "$regx: This region has no KMS keys" "$regx" "$key" fi done } diff --git a/checks/check29 b/checks/check29 index 311e715d..b5023894 100644 --- a/checks/check29 +++ b/checks/check29 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check29="2.9" -CHECK_TITLE_check29="[check29] Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" +CHECK_TITLE_check29="[check29] Ensure VPC Flow Logging is Enabled in all VPCs" CHECK_SCORED_check29="SCORED" CHECK_TYPE_check29="LEVEL2" CHECK_SEVERITY_check29="Medium" @@ -28,21 +31,21 @@ check29(){ 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" + textFail "$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" + textFail "$regx: VPC $vpcx Access Denied trying to describe flow logs" "$regx" "$vpcx" continue fi if [[ $CHECK_FL ]]; then for FL in $CHECK_FL; do - textPass "$regx: VPC $vpcx VPCFlowLog is enabled for LogGroupName: $FL" + textPass "$regx: VPC $vpcx VPCFlowLog is enabled for LogGroupName: $FL" "$regx" "$vpcx" done else - textFail "$regx: VPC $vpcx VPCFlowLog is disabled" + textFail "$regx: VPC $vpcx VPCFlowLog is disabled" "$regx" "$vpcx" fi done done diff --git a/checks/check31 b/checks/check31 index 7674f8a4..4411c6fa 100644 --- a/checks/check31 +++ b/checks/check31 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check31="3.1" -CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" +CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls" CHECK_SCORED_check31="SCORED" CHECK_TYPE_check31="LEVEL1" CHECK_SEVERITY_check31="Medium" diff --git a/checks/check310 b/checks/check310 index 40744be0..0a2d53d9 100644 --- a/checks/check310 +++ b/checks/check310 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check310="3.10" -CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)" +CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes" CHECK_SCORED_check310="SCORED" CHECK_TYPE_check310="LEVEL2" CHECK_SEVERITY_check310="Medium" diff --git a/checks/check311 b/checks/check311 index b36dff27..fb66edb6 100644 --- a/checks/check311 +++ b/checks/check311 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check311="3.11" -CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" +CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)" CHECK_SCORED_check311="SCORED" CHECK_TYPE_check311="LEVEL2" CHECK_SEVERITY_check311="Medium" diff --git a/checks/check312 b/checks/check312 index 702f068e..1de26238 100644 --- a/checks/check312 +++ b/checks/check312 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check312="3.12" -CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" +CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways" CHECK_SCORED_check312="SCORED" CHECK_TYPE_check312="LEVEL1" CHECK_SEVERITY_check312="Medium" diff --git a/checks/check313 b/checks/check313 index 258af60d..2ce23a51 100644 --- a/checks/check313 +++ b/checks/check313 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check313="3.13" -CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)" +CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes" CHECK_SCORED_check313="SCORED" CHECK_TYPE_check313="LEVEL1" CHECK_SEVERITY_check313="Medium" diff --git a/checks/check314 b/checks/check314 index 488663c4..a0d728bb 100644 --- a/checks/check314 +++ b/checks/check314 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check314="3.14" -CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)" +CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes" CHECK_SCORED_check314="SCORED" CHECK_TYPE_check314="LEVEL1" CHECK_SEVERITY_check314="Medium" diff --git a/checks/check32 b/checks/check32 index ff13166b..b932b13a 100644 --- a/checks/check32 +++ b/checks/check32 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check32="3.2" -CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" +CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA" CHECK_SCORED_check32="SCORED" CHECK_TYPE_check32="LEVEL1" CHECK_SEVERITY_check32="Medium" diff --git a/checks/check33 b/checks/check33 index 840e386d..1cd54328 100644 --- a/checks/check33 +++ b/checks/check33 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check33="3.3" -CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)" +CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account" CHECK_SCORED_check33="SCORED" CHECK_TYPE_check33="LEVEL1" CHECK_SEVERITY_check33="Medium" diff --git a/checks/check34 b/checks/check34 index 727512c8..250044e0 100644 --- a/checks/check34 +++ b/checks/check34 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check34="3.4" -CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" +CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes" CHECK_SCORED_check34="SCORED" CHECK_TYPE_check34="LEVEL1" CHECK_SEVERITY_check34="Medium" diff --git a/checks/check35 b/checks/check35 index 13fae612..bae1f254 100644 --- a/checks/check35 +++ b/checks/check35 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check35="3.5" -CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" +CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes" CHECK_SCORED_check35="SCORED" CHECK_TYPE_check35="LEVEL1" CHECK_SEVERITY_check35="Medium" diff --git a/checks/check36 b/checks/check36 index 8ab2a0ef..fc9e4c39 100644 --- a/checks/check36 +++ b/checks/check36 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check36="3.6" -CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" +CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures" CHECK_SCORED_check36="SCORED" CHECK_TYPE_check36="LEVEL2" CHECK_SEVERITY_check36="Medium" diff --git a/checks/check37 b/checks/check37 index 7c891a9e..03f593ea 100644 --- a/checks/check37 +++ b/checks/check37 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check37="3.7" -CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created KMS CMKs (Scored)" +CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created KMS CMKs" CHECK_SCORED_check37="SCORED" CHECK_TYPE_check37="LEVEL2" CHECK_SEVERITY_check37="Medium" diff --git a/checks/check38 b/checks/check38 index eabf8475..9d81443c 100644 --- a/checks/check38 +++ b/checks/check38 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check38="3.8" -CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" +CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes" CHECK_SCORED_check38="SCORED" CHECK_TYPE_check38="LEVEL1" CHECK_SEVERITY_check38="Medium" diff --git a/checks/check39 b/checks/check39 index 05cc9936..aabbd359 100644 --- a/checks/check39 +++ b/checks/check39 @@ -1,12 +1,15 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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: # @@ -34,7 +37,7 @@ # --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check39="3.9" -CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" +CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes" CHECK_SCORED_check39="SCORED" CHECK_TYPE_check39="LEVEL2" CHECK_SEVERITY_check39="Medium" diff --git a/checks/check41 b/checks/check41 index 3231f42f..02f0fbf5 100644 --- a/checks/check41 +++ b/checks/check41 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check41="4.1" -CHECK_TITLE_check41="[check41] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 22 (Scored)" +CHECK_TITLE_check41="[check41] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 22" CHECK_SCORED_check41="SCORED" CHECK_TYPE_check41="LEVEL2" CHECK_SEVERITY_check41="High" @@ -29,10 +32,10 @@ check41(){ 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) if [[ $SG_LIST ]];then for SG in $SG_LIST;do - textFail "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0" "$regx" "$SG" done else - textPass "No Security Groups found in $regx with port 22 TCP open to 0.0.0.0/0" "$regx" + textPass "$regx: No Security Groups found with port 22 TCP open to 0.0.0.0/0" "$regx" "$SG" fi done } diff --git a/checks/check42 b/checks/check42 index da7b50f3..a2bf70fd 100644 --- a/checks/check42 +++ b/checks/check42 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check42="4.2" -CHECK_TITLE_check42="[check42] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389 (Scored)" +CHECK_TITLE_check42="[check42] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389" CHECK_SCORED_check42="SCORED" CHECK_TYPE_check42="LEVEL2" CHECK_SEVERITY_check42="High" @@ -29,10 +32,10 @@ check42(){ 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) if [[ $SG_LIST ]];then for SG in $SG_LIST;do - textFail "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0" "$regx" "$SG" done else - textPass "No Security Groups found in $regx with port 3389 TCP open to 0.0.0.0/0" "$regx" + textPass "$regx: No Security Groups found with port 3389 TCP open to 0.0.0.0/0" "$regx" "$SG" fi done } diff --git a/checks/check43 b/checks/check43 index ae11b6f1..205f4eb3 100644 --- a/checks/check43 +++ b/checks/check43 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check43="4.3" -CHECK_TITLE_check43="[check43] Ensure the default security group of every VPC restricts all traffic (Scored)" +CHECK_TITLE_check43="[check43] Ensure the default security group of every VPC restricts all traffic" CHECK_SCORED_check43="SCORED" CHECK_TYPE_check43="LEVEL2" CHECK_SEVERITY_check43="High" @@ -30,9 +33,9 @@ check43(){ 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 - textFail "Default Security Groups ($CHECK_SGDEFAULT_ID) found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx" + textFail "$regx: Default Security Groups ($CHECK_SGDEFAULT_ID) found that allow 0.0.0.0 IN or OUT traffic" "$regx" "$CHECK_SGDEFAULT_ID" else - textPass "No Default Security Groups ($CHECK_SGDEFAULT_ID) open to 0.0.0.0 found in Region $regx" "$regx" + textPass "$regx: No Default Security Groups ($CHECK_SGDEFAULT_ID) open to 0.0.0.0 found" "$regx" "$CHECK_SGDEFAULT_ID" fi done done diff --git a/checks/check44 b/checks/check44 index 4683abe8..e5328c29 100644 --- a/checks/check44 +++ b/checks/check44 @@ -1,15 +1,18 @@ #!/usr/bin/env bash -# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente # -# This Prowler check is licensed under a -# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# 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 # -# You should have received a copy of the license along with this -# work. If not, see . +# 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_check44="4.4" -CHECK_TITLE_check44="[check44] Ensure routing tables for VPC peering are \"least access\" (Not Scored)" +CHECK_TITLE_check44="[check44] Ensure routing tables for VPC peering are \"least access\"" CHECK_SCORED_check44="NOT_SCORED" CHECK_TYPE_check44="LEVEL2" CHECK_SEVERITY_check44="Medium" @@ -24,11 +27,10 @@ CHECK_CAF_EPIC_check44='Infrastructure Security' check44(){ # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" - textInfo "Looking for VPC peering in all regions... " 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" " -) if [[ $LIST_OF_VPCS_PEERING_CONNECTIONS ]];then - textInfo "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" + 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) #aws ec2 describe-route-tables --filter "Name=vpc-id,Values=vpc-0213e864" --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" $PROFILE_OPT --region $regx # for vpc in $LIST_OF_VPCS; do @@ -36,7 +38,7 @@ check44(){ # done #echo $VPCS_WITH_PEERING else - textPass "$regx: No VPC peering found" "$regx" + textPass "$regx: No VPC peering found" "$regx" "$LIST_OF_VPCS_PEERING_CONNECTIONS" fi done } diff --git a/checks/check45 b/checks/check45 new file mode 100644 index 00000000..d68fc140 --- /dev/null +++ b/checks/check45 @@ -0,0 +1,39 @@ +#!/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_check45="4.5" +CHECK_TITLE_check45="[check45] Ensure no Network ACLs allow ingress from 0.0.0.0/0 to SSH port 22" +CHECK_SCORED_check45="SCORED" +CHECK_TYPE_check45="LEVEL2" +CHECK_SEVERITY_check45="High" +CHECK_ASFF_TYPE_check45="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" +CHECK_ASFF_RESOURCE_TYPE_check45="AwsEc2NetworkAcl" +CHECK_ALTERNATE_check401="check45" +CHECK_SERVICENAME_check45="ec2" +CHECK_RISK_check45='Even having a perimeter firewall; having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.' +CHECK_REMEDIATION_check45='Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.' +CHECK_DOC_check45='https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html' +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) + 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" + done + else + textPass "$regx: No Network ACL found with SSH port 22 open to 0.0.0.0/0" "$regx" "$NACL" + fi + done +} diff --git a/checks/check46 b/checks/check46 new file mode 100644 index 00000000..02c2101b --- /dev/null +++ b/checks/check46 @@ -0,0 +1,39 @@ +#!/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_check46="4.6" +CHECK_TITLE_check46="[check46] Ensure no Network ACLs allow ingress from 0.0.0.0/0 to Microsoft RDP port 3389" +CHECK_SCORED_check46="SCORED" +CHECK_TYPE_check46="LEVEL2" +CHECK_SEVERITY_check46="High" +CHECK_ASFF_TYPE_check46="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" +CHECK_ASFF_RESOURCE_TYPE_check46="AwsEc2NetworkAcl" +CHECK_ALTERNATE_check401="check46" +CHECK_SERVICENAME_check46="ec2" +CHECK_RISK_check46='Even having a perimeter firewall; having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.' +CHECK_REMEDIATION_check46='Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.' +CHECK_DOC_check46='https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html' +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) + 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" + done + else + textPass "$regx: No Network ACL found with Microsoft RDP port 3389 open to 0.0.0.0/0" "$regx" "$NACL" + fi + done +} diff --git a/checks/check_extra71 b/checks/check_extra71 index a0a8ce03..4bf1706c 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra71="7.1" -CHECK_TITLE_extra71="[extra71] Ensure users of groups with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra71="[extra71] Ensure users of groups with AdministratorAccess policy have MFA tokens enabled" CHECK_SCORED_extra71="NOT_SCORED" CHECK_TYPE_extra71="EXTRA" CHECK_SEVERITY_extra71="High" @@ -27,7 +27,7 @@ CHECK_DOC_extra71='https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentia CHECK_CAF_EPIC_extra71='Infrastructure Security' extra71(){ - # "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" + # "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled " ADMIN_GROUPS='' AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --region $REGION --query 'Groups[].GroupName') for grp in $AWS_GROUPS; do @@ -36,7 +36,7 @@ extra71(){ CHECK_ADMIN_GROUP=$($AWSCLI $PROFILE_OPT --region $REGION iam list-attached-group-policies --group-name $grp --output json --query 'AttachedPolicies[].PolicyArn' | grep "arn:${AWS_PARTITION}:iam::aws:policy/AdministratorAccess") if [[ $CHECK_ADMIN_GROUP ]]; then ADMIN_GROUPS="$ADMIN_GROUPS $grp" - textInfo "$grp group provides administrative access" + textInfo "$REGION: $grp group provides administrative access" "$REGION" "$grp" ADMIN_USERS=$($AWSCLI $PROFILE_OPT iam get-group --region $REGION --group-name $grp --output json --query 'Users[].UserName' | grep '"' | cut -d'"' -f2 ) for auser in $ADMIN_USERS; do # users in group are Administrators @@ -44,13 +44,13 @@ extra71(){ # check for user MFA device in credential report USER_MFA_ENABLED=$( cat $TEMP_REPORT_FILE | grep "^$auser," | cut -d',' -f8) if [[ "true" == $USER_MFA_ENABLED ]]; then - textPass "$auser / MFA Enabled / admin via group $grp" + textPass "$REGION: $auser / MFA Enabled / admin via group $grp" "$REGION" "$grp" else - textFail "$auser / MFA DISABLED / admin via group $grp" + textFail "$REGION: $auser / MFA DISABLED / admin via group $grp" "$REGION" "$grp" fi done else - textInfo "$grp group provides non-administrative access" + textInfo "$REGION: $grp group provides non-administrative access" "$REGION" "$grp" fi done } diff --git a/checks/check_extra710 b/checks/check_extra710 index 3a15384e..a1c10252 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra710="7.10" -CHECK_TITLE_extra710="[extra710] Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra710="[extra710] Check for internet facing EC2 Instances" CHECK_SCORED_extra710="NOT_SCORED" CHECK_TYPE_extra710="EXTRA" CHECK_SEVERITY_extra710="Medium" @@ -25,18 +25,17 @@ CHECK_DOC_extra710='https://aws.amazon.com/blogs/aws/aws-web-application-firewal CHECK_CAF_EPIC_extra710='Infrastructure Security' extra710(){ - # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for instances in all regions... " + # "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) if [[ $LIST_OF_PUBLIC_INSTANCES ]];then 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" + textPass "$regx: no Internet Facing EC2 Instances found" "$regx" "$INSTANCE_ID" fi done } diff --git a/checks/check_extra7100 b/checks/check_extra7100 index 8fe3e53b..8e2a3807 100644 --- a/checks/check_extra7100 +++ b/checks/check_extra7100 @@ -37,7 +37,6 @@ extra7100(){ # Learn more: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_permissions-to-switch.html#roles-usingrole-createpolicy LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION --scope Local --query 'Policies[*].[Arn,DefaultVersionId]' | grep -v -e '^None$' | awk -F '\t' '{print $1","$2"\n"}') if [[ $LIST_CUSTOM_POLICIES ]]; then - textInfo "Looking for custom policies: (skipping default policies - it may take few seconds...)" for policy in $LIST_CUSTOM_POLICIES; do POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}') POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}') @@ -72,12 +71,12 @@ extra7100(){ textInfo "STS AssumeRole Policies should only include the complete ARNs for the Roles that the user needs" textInfo "Learn more: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_permissions-to-switch.html#roles-usingrole-createpolicy" for policy in $PERMISSIVE_POLICIES_LIST; do - textFail "Policy $policy allows permissive STS Role assumption" + textFail "$REGION: Policy $policy allows permissive STS Role assumption" "$REGION" "$policy" done else - textPass "No custom policies found that allow permissive STS Role assumption" + textPass "$REGION: No custom policies found that allow permissive STS Role assumption" "$REGION" fi else - textPass "No custom policies found" + textPass "$REGION: No custom policies found" "$REGION" fi } diff --git a/checks/check_extra7101 b/checks/check_extra7101 index aa6b43e4..e1ba8dbb 100644 --- a/checks/check_extra7101 +++ b/checks/check_extra7101 @@ -31,9 +31,9 @@ extra7101(){ 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) if [[ $AUDIT_LOGS_ENABLED ]];then - textPass "$regx: Amazon ES domain $domain AUDIT_LOGS enabled" "$regx" + textPass "$regx: Amazon ES domain $domain AUDIT_LOGS enabled" "$regx" "$domain" else - textFail "$regx: Amazon ES domain $domain AUDIT_LOGS disabled!" "$regx" + textFail "$regx: Amazon ES domain $domain AUDIT_LOGS disabled!" "$regx" "$domain" fi done else diff --git a/checks/check_extra7102 b/checks/check_extra7102 index dc47d115..b9efcc29 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -47,7 +47,7 @@ extra7102(){ else echo $SHODAN_QUERY > $OUTPUT_DIR/shodan-output-$ip.json IP_SHODAN_INFO=$(cat $OUTPUT_DIR/shodan-output-$ip.json | jq -r '. | { ports: .ports, org: .org, country: .country_name }| @text' | tr -d \"\{\}\}\]\[ | tr , '\ ' ) - textFail "$regx: IP $ip is listed in Shodan with data $IP_SHODAN_INFO. More info https://www.shodan.io/host/$ip and $OUTPUT_DIR/shodan-output-$ip.json" "$regx" + textFail "$regx: IP $ip is listed in Shodan with data $IP_SHODAN_INFO. More info https://www.shodan.io/host/$ip and $OUTPUT_DIR/shodan-output-$ip.json" "$regx" "$ip" fi done else diff --git a/checks/check_extra7103 b/checks/check_extra7103 index bd0c8116..558a1d94 100644 --- a/checks/check_extra7103 +++ b/checks/check_extra7103 @@ -31,9 +31,9 @@ extra7103(){ 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) if [[ "${SM_NB_ROOTACCESS}" == "Enabled" ]]; then - textFail "${regx}: Sagemaker Notebook instance $nb_instance has root access enabled" "${regx}" + textFail "${regx}: Sagemaker Notebook instance $nb_instance has root access enabled" "${regx}" "$nb_instance" else - textPass "${regx}: Sagemaker Notebook instance $nb_instance has root access disabled" "${regx}" + textPass "${regx}: Sagemaker Notebook instance $nb_instance has root access disabled" "${regx}" "$nb_instance" fi done else diff --git a/checks/check_extra7104 b/checks/check_extra7104 index d38a43cb..00b9b065 100644 --- a/checks/check_extra7104 +++ b/checks/check_extra7104 @@ -31,9 +31,9 @@ extra7104(){ 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) if [[ "${SM_NB_SUBNETID}" == "None" ]]; then - textFail "${regx}: Sagemaker Notebook instance $nb_instance has VPC settings disabled" "${regx}" + textFail "${regx}: Sagemaker Notebook instance $nb_instance has VPC settings disabled" "${regx}" "$nb_instance" else - textPass "${regx}: Sagemaker Notebook instance $nb_instance is in a VPC" "${regx}" + textPass "${regx}: Sagemaker Notebook instance $nb_instance is in a VPC" "${regx}" "$nb_instance" fi done else diff --git a/checks/check_extra7105 b/checks/check_extra7105 index 39220549..1316a431 100644 --- a/checks/check_extra7105 +++ b/checks/check_extra7105 @@ -31,9 +31,9 @@ extra7105(){ 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) if [[ $SM_NB_NETWORKISOLATION == False ]]; then - textFail "${regx}: SageMaker Model $nb_model_name has network isolation disabled" "${regx}" + textFail "${regx}: SageMaker Model $nb_model_name has network isolation disabled" "${regx}" "$nb_model_name" else - textPass "${regx}: SageMaker Model $nb_model_name has network isolation enabled" "${regx}" + textPass "${regx}: SageMaker Model $nb_model_name has network isolation enabled" "${regx}" "$nb_model_name" fi done else diff --git a/checks/check_extra7106 b/checks/check_extra7106 index 39f62234..e49b8a50 100644 --- a/checks/check_extra7106 +++ b/checks/check_extra7106 @@ -31,9 +31,9 @@ extra7106(){ 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) if [[ $SM_NB_VPCCONFIG == "None" ]]; then - textFail "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings disabled" "${regx}" + textFail "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings disabled" "${regx}" "$nb_model_name" else - textPass "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings enabled" "${regx}" + textPass "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings enabled" "${regx}" "$nb_model_name" fi done else diff --git a/checks/check_extra7107 b/checks/check_extra7107 index 7464387f..2f8c70a6 100644 --- a/checks/check_extra7107 +++ b/checks/check_extra7107 @@ -31,9 +31,9 @@ extra7107(){ 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) if [[ $SM_NB_INTERCONTAINERENCRYPTION == "False" ]]; then - textFail "${regx}: SageMaker Training job $nb_job_name has intercontainer encryption disabled" "${regx}" + textFail "${regx}: SageMaker Training job $nb_job_name has intercontainer encryption disabled" "${regx}" "$nb_job_name" else - textPass "${regx}: SageMaker Training jobs $nb_job_name has intercontainer encryption enabled" "${regx}" + textPass "${regx}: SageMaker Training jobs $nb_job_name has intercontainer encryption enabled" "${regx}" "$nb_job_name" fi done else diff --git a/checks/check_extra7108 b/checks/check_extra7108 index 45c38b7e..f84f6997 100644 --- a/checks/check_extra7108 +++ b/checks/check_extra7108 @@ -31,9 +31,9 @@ extra7108(){ 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) if [[ "${SM_JOB_KMSENCRYPTION}" == "None" ]];then - textFail "${regx}: Sagemaker Trainings job $nb_job_name has KMS encryption disabled" "${regx}" + textFail "${regx}: Sagemaker Trainings job $nb_job_name has KMS encryption disabled" "${regx}" "$nb_job_name" else - textPass "${regx}: Sagemaker Trainings job $nb_job_name has KSM encryption enabled" "${regx}" + textPass "${regx}: Sagemaker Trainings job $nb_job_name has KSM encryption enabled" "${regx}" "$nb_job_name" fi done else diff --git a/checks/check_extra7109 b/checks/check_extra7109 index 5474ce38..80778fd2 100644 --- a/checks/check_extra7109 +++ b/checks/check_extra7109 @@ -31,9 +31,9 @@ extra7109(){ 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) if [[ $SM_NB_NETWORKISOLATION == False ]]; then - textFail "${regx}: Sagemaker Training job $nb_job_name has network isolation disabled" "${regx}" + textFail "${regx}: Sagemaker Training job $nb_job_name has network isolation disabled" "${regx}" "$nb_job_name" else - textPass "${regx}: Sagemaker Training job $nb_job_name has network isolation enabled" "${regx}" + textPass "${regx}: Sagemaker Training job $nb_job_name has network isolation enabled" "${regx}" "$nb_job_name" fi done else diff --git a/checks/check_extra711 b/checks/check_extra711 index b5bf3ee7..4a0b5d66 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra711="7.11" -CHECK_TITLE_extra711="[extra711] Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra711="[extra711] Check for Publicly Accessible Redshift Clusters" CHECK_SCORED_extra711="NOT_SCORED" CHECK_TYPE_extra711="EXTRA" CHECK_SEVERITY_extra711="High" @@ -24,18 +24,17 @@ CHECK_DOC_extra711='https://docs.aws.amazon.com/redshift/latest/mgmt/managing-cl CHECK_CAF_EPIC_extra711='Data Protection' extra711(){ - # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for Redshift clusters in all regions... " + # "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) if [[ $LIST_OF_PUBLIC_REDSHIFT_CLUSTERS ]];then while read -r cluster;do CLUSTER_ID=$(echo $cluster | awk '{ print $1; }') CLUSTER_ENDPOINT=$(echo $cluster | awk '{ print $2; }') - textFail "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" + textFail "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" "$CLUSTER_ID" done <<< "$LIST_OF_PUBLIC_REDSHIFT_CLUSTERS" else - textPass "$regx: no Publicly Accessible Redshift Clusters found" "$regx" + textPass "$regx: no Publicly Accessible Redshift Clusters found" "$regx" "$CLUSTER_ID" fi done } diff --git a/checks/check_extra7110 b/checks/check_extra7110 index fe91f12a..5a6ebefc 100644 --- a/checks/check_extra7110 +++ b/checks/check_extra7110 @@ -31,9 +31,9 @@ extra7110(){ 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) if [[ $SM_NB_SUBNETS == "None" ]]; then - textFail "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output disabled" "${regx}" + textFail "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output disabled" "${regx}" "$nb_job_name" else - textPass "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output enabled" "${regx}" + textPass "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output enabled" "${regx}" "$nb_job_name" fi done else diff --git a/checks/check_extra7111 b/checks/check_extra7111 index f3117ab0..965c6048 100644 --- a/checks/check_extra7111 +++ b/checks/check_extra7111 @@ -31,9 +31,9 @@ extra7111(){ 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) if [[ "${SM_NB_DIRECTINET}" == "Enabled" ]]; then - textFail "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access enabled" "${regx}" + textFail "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access enabled" "${regx}" "$nb_instance" else - textPass "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access disabled" "${regx}" + textPass "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access disabled" "${regx}" "$nb_instance" fi done else diff --git a/checks/check_extra7112 b/checks/check_extra7112 index 5693bf0c..ed954a9d 100644 --- a/checks/check_extra7112 +++ b/checks/check_extra7112 @@ -31,9 +31,9 @@ extra7112(){ 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) if [[ "${SM_NB_KMSKEY}" == "None" ]]; then - textFail "${regx}: Sagemaker Notebook instance $nb_instance has data encryption disabled" "${regx}" + textFail "${regx}: Sagemaker Notebook instance $nb_instance has data encryption disabled" "${regx}" "$nb_instance" else - textPass "${regx}: Sagemaker Notebook instance $nb_instance has data encryption enabled" "${regx}" + textPass "${regx}: Sagemaker Notebook instance $nb_instance has data encryption enabled" "${regx}" "$nb_instance" fi done else diff --git a/checks/check_extra7113 b/checks/check_extra7113 index a9dcbcce..3412a56b 100644 --- a/checks/check_extra7113 +++ b/checks/check_extra7113 @@ -23,7 +23,7 @@ # [--apply-immediately | --no-apply-immediately] CHECK_ID_extra7113="7.113" -CHECK_TITLE_extra7113="[extra7113] Check if RDS instances have deletion protection enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra7113="[extra7113] Check if RDS instances have deletion protection enabled " CHECK_SCORED_extra7113="NOT_SCORED" CHECK_TYPE_extra7113="EXTRA" CHECK_SEVERITY_extra7113="Medium" @@ -36,20 +36,19 @@ CHECK_DOC_extra7113='https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER CHECK_CAF_EPIC_extra7113='Data Protection' extra7113(){ - textInfo "Looking for RDS Volumes in all regions... " 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[?Engine != 'docdb'].DBInstanceIdentifier" --output text) 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) if [[ $IS_DELETIONPROTECTION == "False" ]]; then - textFail "$regx: RDS instance $rdsinstance deletion protection is not enabled!" "$regx" + textFail "$regx: RDS instance $rdsinstance deletion protection is not enabled!" "$regx" "$rdsinstance" else - textPass "$regx: RDS instance $rdsinstance deletion protection is enabled" "$regx" + textPass "$regx: RDS instance $rdsinstance deletion protection is enabled" "$regx" "$rdsinstance" fi done else - textInfo "$regx: No RDS instances found" "$regx" + textInfo "$regx: No RDS instances found" "$regx" "$rdsinstance" fi done } diff --git a/checks/check_extra7114 b/checks/check_extra7114 index 0fa3a7b7..93c7906a 100644 --- a/checks/check_extra7114 +++ b/checks/check_extra7114 @@ -34,12 +34,12 @@ extra7114(){ if [[ ! -z "$ENDPOINT_SC" ]]; then ENDPOINT_SC_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${ENDPOINT_SC}" $PROFILE_OPT --region $regx --query 'SecurityConfiguration.EncryptionConfiguration.S3Encryption[0].S3EncryptionMode' --output text) if [[ "$ENDPOINT_SC_ENCRYPTION" == "DISABLED" ]]; then - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have S3 encryption enabled!" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have S3 encryption enabled!" "$regx" "$ENDPOINT_NAME" else - textPass "$regx: Glue development endpoint $ENDPOINT_NAME has S3 encryption enabled" "$regx" + textPass "$regx: Glue development endpoint $ENDPOINT_NAME has S3 encryption enabled" "$regx" "$ENDPOINT_NAME" fi else - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" "$ENDPOINT_NAME" fi done else diff --git a/checks/check_extra7115 b/checks/check_extra7115 index cc883edb..14e4e9b8 100644 --- a/checks/check_extra7115 +++ b/checks/check_extra7115 @@ -31,9 +31,9 @@ extra7115(){ CONNECTION_NAME=$(echo $connection | base64 --decode | jq -r '.Name' ) CONNECTION_SSL_STATE=$(echo $connection | base64 --decode | jq -r '.SSL') if [[ "$CONNECTION_SSL_STATE" == "false" ]]; then - textFail "$regx: Glue connection $CONNECTION_NAME has SSL connection disabled" "$regx" + textFail "$regx: Glue connection $CONNECTION_NAME has SSL connection disabled" "$regx" "$CONNECTION_NAME" else - textPass "$regx: Glue connection $CONNECTION_NAME has SSL connection enabled" "$regx" + textPass "$regx: Glue connection $CONNECTION_NAME has SSL connection enabled" "$regx" "$CONNECTION_NAME" fi done else diff --git a/checks/check_extra7118 b/checks/check_extra7118 index 524ac4c2..12cc7b08 100644 --- a/checks/check_extra7118 +++ b/checks/check_extra7118 @@ -35,17 +35,17 @@ extra7118(){ S3_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${SECURITY_CONFIGURATION}" $PROFILE_OPT --region $regx --output text --query 'SecurityConfiguration.EncryptionConfiguration.S3Encryption[0].S3EncryptionMode') if [[ "$S3_ENCRYPTION" == "DISABLED" ]]; then if [[ ! -z "$JOB_ENCRYPTION" ]]; then - textPass "$regx: Glue job $JOB_NAME does have $JOB_ENCRYPTION for S3 encryption enabled" "$regx" + textPass "$regx: Glue job $JOB_NAME does have $JOB_ENCRYPTION for S3 encryption enabled" "$regx" "$JOB_NAME" else - textFail "$regx: Glue job $JOB_NAME does not have S3 encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have S3 encryption enabled" "$regx" "$JOB_NAME" fi else - textPass "$regx: Glue job $JOB_NAME does have $S3_ENCRYPTION for S3 encryption enabled" "$regx" + textPass "$regx: Glue job $JOB_NAME does have $S3_ENCRYPTION for S3 encryption enabled" "$regx" "$JOB_NAME" fi elif [[ ! -z "$JOB_ENCRYPTION" ]]; then - textPass "$regx: Glue job $JOB_NAME does have $JOB_ENCRYPTION for S3 encryption enabled" "$regx" + textPass "$regx: Glue job $JOB_NAME does have $JOB_ENCRYPTION for S3 encryption enabled" "$regx" "$JOB_NAME" else - textFail "$regx: Glue job $JOB_NAME does not have S3 encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have S3 encryption enabled" "$regx" "$JOB_NAME" fi done else diff --git a/checks/check_extra7119 b/checks/check_extra7119 index fbd035dc..4f6e904b 100644 --- a/checks/check_extra7119 +++ b/checks/check_extra7119 @@ -34,12 +34,12 @@ extra7119(){ if [[ ! -z "$ENDPOINT_SC" ]]; then ENDPOINT_SC_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${ENDPOINT_SC}" $PROFILE_OPT --region $regx --query 'SecurityConfiguration.EncryptionConfiguration.CloudWatchEncryption.CloudWatchEncryptionMode' --output text) if [[ $ENDPOINT_SC_ENCRYPTION == "DISABLED" ]]; then - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have CloudWatch logs encryption enabled!" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have CloudWatch logs encryption enabled!" "$regx" "$ENDPOINT_NAME" else - textPass "$regx: Glue development endpoint $ENDPOINT_NAME has CloudWatch logs encryption enabled" "$regx" + textPass "$regx: Glue development endpoint $ENDPOINT_NAME has CloudWatch logs encryption enabled" "$regx" "$ENDPOINT_NAME" fi else - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" "$ENDPOINT_NAME" fi done else diff --git a/checks/check_extra712 b/checks/check_extra712 index 21c9fcae..754c3559 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra712="7.12" -CHECK_TITLE_extra712="[extra712] Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra712="[extra712] Check if Amazon Macie is enabled" CHECK_SCORED_extra712="NOT_SCORED" CHECK_TYPE_extra712="EXTRA" CHECK_SEVERITY_extra712="Low" @@ -24,12 +24,12 @@ CHECK_DOC_extra712='https://docs.aws.amazon.com/macie/latest/user/getting-starte CHECK_CAF_EPIC_extra712='Data Protection' extra712(){ -# textInfo "No API commands available to check if Macie is enabled," -# textInfo "just looking if IAM Macie related permissions exist. " +# "No API commands available to check if Macie is enabled," +# "just looking if IAM Macie related permissions exist. " MACIE_IAM_ROLES_CREATED=$($AWSCLI iam list-roles $PROFILE_OPT --query 'Roles[*].Arn'|grep AWSMacieServiceCustomer|wc -l) if [[ $MACIE_IAM_ROLES_CREATED -eq 2 ]];then - textPass "Macie related IAM roles exist so it might be enabled. Check it out manually" + textPass "$REGION: Macie related IAM roles exist so it might be enabled. Check it out manually" "$REGION" else - textFail "No Macie related IAM roles found. It is most likely not to be enabled" + textFail "$REGION: No Macie related IAM roles found. It is most likely not to be enabled" "$REGION" fi } diff --git a/checks/check_extra7120 b/checks/check_extra7120 index 553a37db..d4217ed2 100644 --- a/checks/check_extra7120 +++ b/checks/check_extra7120 @@ -33,12 +33,12 @@ extra7120(){ if [[ ! -z "$SECURITY_CONFIGURATION" ]]; then CLOUDWATCH_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${SECURITY_CONFIGURATION}" $PROFILE_OPT --region $regx --output text --query 'SecurityConfiguration.EncryptionConfiguration.CloudWatchEncryption.CloudWatchEncryptionMode') if [[ "$CLOUDWATCH_ENCRYPTION" == "DISABLED" ]]; then - textFail "$regx: Glue job $JOB_NAME does not have CloudWatch Logs encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have CloudWatch Logs encryption enabled" "$regx" "$JOB_NAME" else - textPass "$regx: Glue job $JOB_NAME does have $CLOUDWATCH_ENCRYPTION CloudWatch Logs encryption enabled" "$regx" + textPass "$regx: Glue job $JOB_NAME does have $CLOUDWATCH_ENCRYPTION CloudWatch Logs encryption enabled" "$regx" "$JOB_NAME" fi else - textFail "$regx: Glue job $JOB_NAME does not have CloudWatch Logs encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have CloudWatch Logs encryption enabled" "$regx" "$JOB_NAME" fi done else diff --git a/checks/check_extra7121 b/checks/check_extra7121 index 9bfe383e..032bcfa5 100644 --- a/checks/check_extra7121 +++ b/checks/check_extra7121 @@ -34,12 +34,12 @@ extra7121(){ if [[ ! -z "$ENDPOINT_SC" ]]; then ENDPOINT_SC_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${ENDPOINT_SC}" $PROFILE_OPT --region $regx --query 'SecurityConfiguration.EncryptionConfiguration.JobBookmarksEncryption.JobBookmarksEncryptionMode' --output text) if [[ "$ENDPOINT_SC_ENCRYPTION" == "DISABLED" ]]; then - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have Job Bookmark encryption enabled!" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have Job Bookmark encryption enabled!" "$regx" "$ENDPOINT_NAME" else - textPass "$regx: Glue development endpoint $ENDPOINT_NAME has Job Bookmark encryption enabled" "$regx" + textPass "$regx: Glue development endpoint $ENDPOINT_NAME has Job Bookmark encryption enabled" "$regx" "$ENDPOINT_NAME" fi else - textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" + textFail "$regx: Glue development endpoint $ENDPOINT_NAME does not have security configuration" "$regx" "$ENDPOINT_NAME" fi done else diff --git a/checks/check_extra7122 b/checks/check_extra7122 index de2c2b47..1b4f8d27 100644 --- a/checks/check_extra7122 +++ b/checks/check_extra7122 @@ -33,12 +33,12 @@ extra7122(){ if [[ ! -z "$SECURITY_CONFIGURATION" ]]; then JOB_BOOKMARK_ENCRYPTION=$($AWSCLI glue get-security-configuration --name "${SECURITY_CONFIGURATION}" $PROFILE_OPT --region $regx --output text --query 'SecurityConfiguration.EncryptionConfiguration.JobBookmarksEncryption.JobBookmarksEncryptionMode') if [[ "$JOB_BOOKMARK_ENCRYPTION" == "DISABLED" ]]; then - textFail "$regx: Glue job $JOB_NAME does not have Job bookmark encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have Job bookmark encryption enabled" "$regx" "$JOB_NAME" else - textPass "$regx: Glue job $JOB_NAME does have $JOB_BOOKMARK_ENCRYPTION for Job bookmark encryption enabled" "$regx" + textPass "$regx: Glue job $JOB_NAME does have $JOB_BOOKMARK_ENCRYPTION for Job bookmark encryption enabled" "$regx" "$JOB_NAME" fi else - textFail "$regx: Glue job $JOB_NAME does not have Job bookmark encryption enabled" "$regx" + textFail "$regx: Glue job $JOB_NAME does not have Job bookmark encryption enabled" "$regx" "$JOB_NAME" fi done else diff --git a/checks/check_extra7123 b/checks/check_extra7123 index 0c96f273..c462f749 100644 --- a/checks/check_extra7123 +++ b/checks/check_extra7123 @@ -30,7 +30,7 @@ extra7123(){ if [[ $LIST_OF_USERS_WITH_2ACCESS_KEYS ]]; then # textFail "Users with access key 1 older than 90 days:" for user in $LIST_OF_USERS_WITH_2ACCESS_KEYS; do - textFail "User $user has 2 active access keys" + textFail "User $user has 2 active access keys" "$REGION" "$user" done else textPass "No users with 2 active access keys" diff --git a/checks/check_extra7124 b/checks/check_extra7124 index 739ede63..df02efaf 100644 --- a/checks/check_extra7124 +++ b/checks/check_extra7124 @@ -33,12 +33,12 @@ extra7124(){ LIST_EC2_UNMANAGED=$(echo ${LIST_SSM_MANAGED_INSTANCES[@]} ${LIST_EC2_INSTANCES[@]} | tr ' ' '\n' | sort | uniq -u) if [[ $LIST_EC2_UNMANAGED ]]; then for instance in $LIST_EC2_UNMANAGED; do - textFail "$regx: EC2 instance $instance is not managed by Systems Manager" "$regx" + textFail "$regx: EC2 instance $instance is not managed by Systems Manager" "$regx" "$instance" done fi if [[ $LIST_SSM_MANAGED_INSTANCES ]]; then for instance in $LIST_SSM_MANAGED_INSTANCES; do - textPass "$regx: EC2 instance $instance is managed by Systems Manager" "$regx" + textPass "$regx: EC2 instance $instance is managed by Systems Manager" "$regx" "$instance" done fi else diff --git a/checks/check_extra7125 b/checks/check_extra7125 index 8aabe4d3..545d6d8b 100644 --- a/checks/check_extra7125 +++ b/checks/check_extra7125 @@ -34,9 +34,9 @@ extra7125(){ if [[ $MFA_TYPE == "mfa" || $MFA_TYPE == "sms-mfa" ]]; then textInfo "User $user has virtual MFA enabled" elif [[ $MFA_TYPE == "" ]]; then - textFail "User $user has not hardware MFA enabled" + textFail "User $user has not hardware MFA enabled" "$REGION" "$user" else - textPass "User $user has hardware MFA enabled" + textPass "User $user has hardware MFA enabled" "$REGION" "$user" fi done else diff --git a/checks/check_extra7126 b/checks/check_extra7126 index f1b80877..6017afa4 100644 --- a/checks/check_extra7126 +++ b/checks/check_extra7126 @@ -26,16 +26,16 @@ CHECK_CAF_EPIC_extra7126='Data Protection' extra7126(){ for regx in $REGIONS; do - LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --output text |grep -v :alias/aws/ |awk '{ print $4 }') + LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --query "Aliases[].[AliasName,TargetKeyId]" --output text |grep -v ^alias/aws/ |awk '{ print $2 }') if [[ $LIST_OF_CUSTOMER_KMS_KEYS ]];then for key in $LIST_OF_CUSTOMER_KMS_KEYS; do CHECK_STATUS=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --output json | jq -r '.KeyMetadata.KeyState') if [[ $CHECK_STATUS == "PendingDeletion" ]]; then textInfo "$regx: KMS key $key is pending deletion" "$regx" elif [[ $CHECK_STATUS == "Disabled" ]]; then - textInfo "$regx: KMS key $key is disabled" "$regx" + textInfo "$regx: KMS key $key is disabled" "$regx" "$key" else - textPass "$regx: KMS key $key is not disabled or pending deletion" "$regx" + textPass "$regx: KMS key $key is not disabled or pending deletion" "$regx" "$key" fi done else diff --git a/checks/check_extra7127 b/checks/check_extra7127 index ecc725c1..cc23e4b6 100644 --- a/checks/check_extra7127 +++ b/checks/check_extra7127 @@ -32,12 +32,12 @@ extra7127(){ if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES || $COMPLIANT_SSM_MANAGED_INSTANCES ]]; then if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES ]]; then for instance in $NON_COMPLIANT_SSM_MANAGED_INSTANCES; do - textFail "$regx: EC2 managed instance $instance is non-compliant" "$regx" + textFail "$regx: EC2 managed instance $instance is non-compliant" "$regx" "$instance" done fi if [[ $COMPLIANT_SSM_MANAGED_INSTANCES ]]; then for instance in $COMPLIANT_SSM_MANAGED_INSTANCES; do - textPass "$regx: EC2 managed instance $instance is compliant" "$regx" + textPass "$regx: EC2 managed instance $instance is compliant" "$regx" "$instance" done fi else diff --git a/checks/check_extra7128 b/checks/check_extra7128 index 27be1f66..20182e8c 100644 --- a/checks/check_extra7128 +++ b/checks/check_extra7128 @@ -31,9 +31,9 @@ extra7128(){ 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) if [[ $DDB_TABLE_WITH_KMS == "KMS" ]]; then - textPass "$regx: DynamoDB table $table does have KMS encryption enabled" "$regx" + textPass "$regx: DynamoDB table $table does have KMS encryption enabled" "$regx" "$table" else - textInfo "$regx: DynamoDB table $table does have DEFAULT encryption enabled" "$regx" + textInfo "$regx: DynamoDB table $table does have DEFAULT encryption enabled" "$regx" "$table" fi done else diff --git a/checks/check_extra7129 b/checks/check_extra7129 index 130c8074..ddeb1c77 100644 --- a/checks/check_extra7129 +++ b/checks/check_extra7129 @@ -28,30 +28,45 @@ 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_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) + if [[ $LIST_OF_ELBSV2 ]]; then for alb in $LIST_OF_ELBSV2; do - if [[ $LIST_OF_WAFV2_WEBACL_ARN ]]; then + if [[ ${#LIST_OF_WAFV2_WEBACL_ARN[@]} -gt 0 || ${#LIST_OF_WAFV1_WEBACL_WEBACLID[@]} -gt 0 ]]; then WAF_PROTECTED_ALBS=() for wafaclarn in $LIST_OF_WAFV2_WEBACL_ARN; do ALB_RESOURCES_IN_WEBACL=$($AWSCLI wafv2 list-resources-for-web-acl $PROFILE_OPT --web-acl-arn $wafaclarn --region=$regx --resource-type APPLICATION_LOAD_BALANCER --query ResourceArns --output text | xargs -n1 | awk -F'/' '{ print $3 }'| grep $alb) - if [[ $ALB_RESOURCES_IN_WEBACL ]]; then + if [[ $ALB_RESOURCES_IN_WEBACL ]]; then WAF_PROTECTED_ALBS+=($wafaclarn) fi done - if [[ ${#WAF_PROTECTED_ALBS[@]} -gt 0 ]]; then - for wafaclarn in "${WAF_PROTECTED_ALBS[@]}"; do - WAFV2_WEBACL_ARN_SHORT=$(echo $wafaclarn | awk -F'/' '{ print $3 }') - textPass "$regx: Application Load Balancer $alb is protected by WAFv2 ACL $WAFV2_WEBACL_ARN_SHORT" "$regx" - done + for wafv1aclid in $LIST_OF_WAFV1_WEBACL_WEBACLID; do + ALB_RESOURCES_IN_WEBACL=$($AWSCLI waf-regional list-resources-for-web-acl $PROFILE_OPT --web-acl-id $wafv1aclid --region=$regx --resource-type APPLICATION_LOAD_BALANCER --output text --query "[ResourceArns]"| grep $alb) + if [[ $ALB_RESOURCES_IN_WEBACL ]]; then + WAFv1_PROTECTED_ALBS+=($wafv1aclid) + fi + done + if [[ ${#WAF_PROTECTED_ALBS[@]} -gt 0 || ${#WAFv1_PROTECTED_ALBS[@]} -gt 0 ]]; then + if [[ ${#WAF_PROTECTED_ALBS[@]} -gt 0 ]]; then + for wafaclarn in "${WAF_PROTECTED_ALBS[@]}"; do + WAFV2_WEBACL_ARN_SHORT=$(echo $wafaclarn | awk -F'/' '{ print $3 }') + textPass "$regx: Application Load Balancer $alb is protected by WAFv2 ACL $WAFV2_WEBACL_ARN_SHORT" "$regx" "$alb" + done + fi + if [[ ${#WAFv1_PROTECTED_ALBS[@]} -gt 0 ]]; then + for wafv1aclid in "${WAFv1_PROTECTED_ALBS[@]}"; do + textPass "$regx: Application Load Balancer $alb is protected by WAFv1 ACL $wafv1aclid" "$regx" "$alb" + done + fi else - textFail "$regx: Application Load Balancer $alb is not protected by WAFv2 ACL" "$regx" + textFail "$regx: Application Load Balancer $alb is not protected by WAF ACL" "$regx" "$alb" fi - else - textFail "$regx: Application Load Balancer $alb is not protected no WAFv2 ACL found" "$regx" + else + textFail "$regx: Application Load Balancer $alb is not protected no WAF ACL found" "$regx" "$alb" fi - done + done else textInfo "$regx: No Application Load Balancers found" "$regx" - fi + fi done } \ No newline at end of file diff --git a/checks/check_extra713 b/checks/check_extra713 index 6002ac8d..7a83b9bb 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra713="7.13" -CHECK_TITLE_extra713="[extra713] Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra713="[extra713] Check if GuardDuty is enabled" CHECK_SCORED_extra713="NOT_SCORED" CHECK_TYPE_extra713="EXTRA" CHECK_SEVERITY_extra713="High" @@ -25,7 +25,7 @@ CHECK_DOC_extra713='https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_se CHECK_CAF_EPIC_extra713='Data Protection' extra713(){ - # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if GuardDuty is enabled " for regx in $REGIONS; do LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text --query DetectorIds[*] 2> /dev/null) RESULT=$? @@ -34,9 +34,9 @@ extra713(){ while read -r detector;do DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --query "Status" --output text|grep ENABLED) if [[ $DETECTOR_ENABLED ]]; then - textPass "$regx: GuardDuty detector $detector enabled" "$regx" + textPass "$regx: GuardDuty detector $detector enabled" "$regx" "$detector" else - textFail "$regx: GuardDuty detector $detector configured but suspended" "$regx" + textFail "$regx: GuardDuty detector $detector configured but suspended" "$regx" "$detector" fi done <<< "$LIST_OF_GUARDDUTY_DETECTORS" else diff --git a/checks/check_extra7130 b/checks/check_extra7130 index 4a712973..a302f0d4 100644 --- a/checks/check_extra7130 +++ b/checks/check_extra7130 @@ -25,7 +25,6 @@ CHECK_DOC_extra7130='https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-e CHECK_CAF_EPIC_extra7130='Data Protection' extra7130(){ - textInfo "Looking for SNS Topics in all regions... " for regx in $REGIONS; do LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query 'Topics[*].TopicArn' --output text) if [[ $LIST_SNS ]];then @@ -33,9 +32,9 @@ extra7130(){ SHORT_TOPIC=$(echo $topic | awk -F ":" '{print $NF}') SNS_ENCRYPTION=$($AWSCLI sns get-topic-attributes $PROFILE_OPT --region $regx --topic-arn $topic --query 'Attributes.KmsMasterKeyId' --output text) if [[ "None" == $SNS_ENCRYPTION ]]; then - textFail "$regx: $SHORT_TOPIC is not encrypted!" "$regx" + textFail "$regx: $SHORT_TOPIC is not encrypted!" "$regx" "$SHORT_TOPIC" else - textPass "$regx: $SHORT_TOPIC is encrypted" "$regx" + textPass "$regx: $SHORT_TOPIC is encrypted" "$regx" "$SHORT_TOPIC" fi done else diff --git a/checks/check_extra7131 b/checks/check_extra7131 index fc8266a1..946f1682 100644 --- a/checks/check_extra7131 +++ b/checks/check_extra7131 @@ -32,13 +32,13 @@ extra7131(){ RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') RDS_AUTOMINORUPGRADE_FLAG=$(echo $rds_instance | awk '{ print $2; }') if [[ $RDS_AUTOMINORUPGRADE_FLAG == "True" ]];then - textPass "$regx: RDS instance: $RDS_NAME is has minor version upgrade enabled" "$regx" + textPass "$regx: RDS instance: $RDS_NAME is has minor version upgrade enabled" "$regx" "$RDS_NAME" else - textFail "$regx: RDS instance: $RDS_NAME does not have minor version upgrade enabled" "$regx" + textFail "$regx: RDS instance: $RDS_NAME does not have minor version upgrade enabled" "$regx" "$RDS_NAME" fi done <<< "$LIST_OF_RDS_INSTANCES" else - textInfo "$regx: no RDS instances found" "$regx" + textInfo "$regx: no RDS instances found" "$regx" "$RDS_NAME" fi done } diff --git a/checks/check_extra7132 b/checks/check_extra7132 index eb64827d..5eefb58f 100644 --- a/checks/check_extra7132 +++ b/checks/check_extra7132 @@ -25,19 +25,19 @@ 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[*].DBInstanceIdentifier' --output text) + RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text) if [[ $RDS_INSTANCES ]];then for rdsinstance in ${RDS_INSTANCES}; do RDS_NAME="$rdsinstance" MONITORING_FLAG=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].[EnhancedMonitoringResourceArn]' --output text) if [[ $MONITORING_FLAG == "None" ]];then - textFail "$regx: RDS instance: $RDS_NAME has enhanced monitoring disabled!" "$rex" + textFail "$regx: RDS instance: $RDS_NAME has enhanced monitoring disabled!" "$rex" "$RDS_NAME" else - textPass "$regx: RDS instance: $RDS_NAME has enhanced monitoring enabled." "$regx" + textPass "$regx: RDS instance: $RDS_NAME has enhanced monitoring enabled." "$regx" "$RDS_NAME" fi done else - textInfo "$regx: no RDS instances found" "$regx" + textInfo "$regx: no RDS instances found" "$regx" "$RDS_NAME" fi done } diff --git a/checks/check_extra7133 b/checks/check_extra7133 index 2be3d662..c2eefd5e 100644 --- a/checks/check_extra7133 +++ b/checks/check_extra7133 @@ -25,19 +25,19 @@ 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[*].DBInstanceIdentifier' --output text) + RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query "DBInstances[?Engine != 'docdb'].DBInstanceIdentifier" --output text) if [[ $RDS_INSTANCES ]];then for rdsinstance in ${RDS_INSTANCES}; do RDS_NAME="$rdsinstance" MULTIAZ_FLAG=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].MultiAZ' --output text) if [[ $MULTIAZ_FLAG == "True" ]];then - textPass "$regx: RDS instance: $RDS_NAME has multi-AZ enabled" "$rex" + textPass "$regx: RDS instance: $RDS_NAME has multi-AZ enabled" "$regx" "$RDS_NAME" else - textFail "$regx: RDS instance: $RDS_NAME has multi-AZ disabled!" "$regx" + textFail "$regx: RDS instance: $RDS_NAME has multi-AZ disabled!" "$regx" "$RDS_NAME" fi done else - textInfo "$regx: no RDS instances found" "$regx" + textInfo "$regx: no RDS instances found" "$regx" "$RDS_NAME" fi done } diff --git a/checks/check_extra7134 b/checks/check_extra7134 new file mode 100644 index 00000000..4d649f83 --- /dev/null +++ b/checks/check_extra7134 @@ -0,0 +1,37 @@ +#!/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_extra7134="7.134" +CHECK_TITLE_extra7134="[extra7134] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to FTP ports 20 or 21 " +CHECK_SCORED_extra7134="NOT_SCORED" +CHECK_TYPE_extra7134="EXTRA" +CHECK_SEVERITY_extra7134="High" +CHECK_ASFF_RESOURCE_TYPE_extra7134="AwsEc2SecurityGroup" +CHECK_ALTERNATE_check7134="extra7134" +CHECK_SERVICENAME_extra7134="ec2" +CHECK_RISK_extra7134='If Security groups are not properly configured the attack surface is increased. ' +CHECK_REMEDIATION_extra7134='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.' +CHECK_DOC_extra7134='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html' +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) + 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" + done + else + textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for FTP ports" "$regx" "$SG" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7135 b/checks/check_extra7135 new file mode 100644 index 00000000..42a27bfb --- /dev/null +++ b/checks/check_extra7135 @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +CHECK_ID_extra7135="7.135" +CHECK_TITLE_extra7135="[extra7135] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Kafka port 9092 " +CHECK_SCORED_extra7135="NOT_SCORED" +CHECK_TYPE_extra7135="EXTRA" +CHECK_SEVERITY_extra7135="High" +CHECK_ASFF_RESOURCE_TYPE_extra7135="AwsEc2SecurityGroup" +CHECK_ALTERNATE_check7135="extra7135" +CHECK_SERVICENAME_extra7135="ec2" +CHECK_RISK_extra7135='If Security groups are not properly configured the attack surface is increased. ' +CHECK_REMEDIATION_extra7135='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.' +CHECK_DOC_extra7135='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html' +CHECK_CAF_EPIC_extra7135='Infrastructure Security' + +extra7135(){ + for regx in $REGIONS; do + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`9092` && ToPort==`9092`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + if [[ $SG_LIST ]];then + for SG in $SG_LIST;do + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Kafka ports" "$regx" "$SG" + done + else + textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Kafka ports" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7136 b/checks/check_extra7136 new file mode 100644 index 00000000..7b440031 --- /dev/null +++ b/checks/check_extra7136 @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +CHECK_ID_extra7136="7.136" +CHECK_TITLE_extra7136="[extra7136] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Telnet port 23 " +CHECK_SCORED_extra7136="NOT_SCORED" +CHECK_TYPE_extra7136="EXTRA" +CHECK_SEVERITY_extra7136="High" +CHECK_ASFF_RESOURCE_TYPE_extra7136="AwsEc2SecurityGroup" +CHECK_ALTERNATE_check7136="extra7136" +CHECK_SERVICENAME_extra7136="ec2" +CHECK_RISK_extra7136='If Security groups are not properly configured the attack surface is increased. ' +CHECK_REMEDIATION_extra7136='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.' +CHECK_DOC_extra7136='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html' +CHECK_CAF_EPIC_extra7136='Infrastructure Security' + +extra7136(){ + for regx in $REGIONS; do + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`23` && ToPort==`23`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + if [[ $SG_LIST ]];then + for SG in $SG_LIST;do + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Telnet ports" "$regx" "$SG" + done + else + textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Telnet ports" "$regx" "$SG" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7137 b/checks/check_extra7137 new file mode 100644 index 00000000..754acc5f --- /dev/null +++ b/checks/check_extra7137 @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +CHECK_ID_extra7137="7.137" +CHECK_TITLE_extra7137="[extra7137] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Windows SQL Server ports 1433 or 1434 " +CHECK_SCORED_extra7137="NOT_SCORED" +CHECK_TYPE_extra7137="EXTRA" +CHECK_SEVERITY_extra7137="High" +CHECK_ASFF_RESOURCE_TYPE_extra7137="AwsEc2SecurityGroup" +CHECK_ALTERNATE_check7137="extra7137" +CHECK_SERVICENAME_extra7137="ec2" +CHECK_RISK_extra7137='If Security groups are not properly configured the attack surface is increased. ' +CHECK_REMEDIATION_extra7137='Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.' +CHECK_DOC_extra7137='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html' +CHECK_CAF_EPIC_extra7137='Infrastructure Security' + +extra7137(){ + for regx in $REGIONS; do + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`1433` && ToPort==`1434`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + if [[ $SG_LIST ]];then + for SG in $SG_LIST;do + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Microsoft SQL Server ports" "$regx" "$SG" + done + else + textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Microsoft SQL Server ports" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7138 b/checks/check_extra7138 new file mode 100644 index 00000000..c1704c67 --- /dev/null +++ b/checks/check_extra7138 @@ -0,0 +1,38 @@ +#!/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_extra7138="7.138" +CHECK_TITLE_extra7138="[extra7138] Ensure no Network ACLs allow ingress from 0.0.0.0/0 to any port" +CHECK_SCORED_extra7138="NOT SCORED" +CHECK_TYPE_extra7138="LEVEL2" +CHECK_SEVERITY_extra7138="High" +CHECK_ASFF_TYPE_extra7138="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" +CHECK_ASFF_RESOURCE_TYPE_extra7138="AwsEc2NetworkAcl" +CHECK_ALTERNATE_check7138="extra7138" +CHECK_SERVICENAME_extra7138="ec2" +CHECK_RISK_extra7138='Even having a perimeter firewall; having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.' +CHECK_REMEDIATION_extra7138='Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.' +CHECK_DOC_extra7138='https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html' +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) + 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" + done + else + textPass "$regx: No Network ACL found with any port open to 0.0.0.0/0" "$regx" "$NACL" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7139 b/checks/check_extra7139 new file mode 100644 index 00000000..0b635a10 --- /dev/null +++ b/checks/check_extra7139 @@ -0,0 +1,43 @@ +#!/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_extra7139="7.139" +CHECK_TITLE_extra7139="[extra7139] There are High severity GuardDuty findings " +CHECK_SCORED_extra7139="NOT_SCORED" +CHECK_TYPE_extra7139="EXTRA" +CHECK_SEVERITY_extra7139="High" +CHECK_ASFF_RESOURCE_TYPE_extra7139="AwsGuardDutyDetector" +CHECK_ALTERNATE_check7139="extra7139" +CHECK_SERVICENAME_extra7139="guardduty" +CHECK_RISK_extra7139='If critical findings are not addressed threats can spread in the environment.' +CHECK_REMEDIATION_extra7139='Review and remediate critical GuardDuty findings as quickly as possible.' +CHECK_DOC_extra7139='https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html' +CHECK_CAF_EPIC_extra7139='Incident Response' +extra7139(){ + + for regx in $REGIONS; do + DETECTORS_LIST="" + DETECTORS_LIST=$($AWSCLI guardduty list-detectors --query DetectorIds $PROFILE_OPT --region $regx --output text) + if [[ $DETECTORS_LIST ]];then + for DETECTOR in $DETECTORS_LIST;do + FINDINGS_COUNT="" + FINDINGS_COUNT=$($AWSCLI $PROFILE_OPT --region $regx --output text guardduty list-findings --detector-id $DETECTOR --finding-criteria '{"Criterion":{"severity": {"Eq":["8"]}}}' 2> /dev/null | wc -l | xargs) # Severity LOW=2, MED=4, HIGH=8 + if [[ $FINDINGS_COUNT -gt 0 ]];then + textFail "$regx: GuardDuty has $FINDINGS_COUNT high severity findings." "$regx" + else + textPass "$regx: GuardDuty has no high severity findings." "$regx" + fi + done + else + textInfo "$regx: No GuardDuty detectors found." "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra714 b/checks/check_extra714 index 38bddcc1..27681e1f 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra714="7.14" -CHECK_TITLE_extra714="[extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra714="[extra714] Check if CloudFront distributions have logging enabled" CHECK_SCORED_extra714="NOT_SCORED" CHECK_TYPE_extra714="EXTRA" CHECK_SEVERITY_extra714="Medium" @@ -24,18 +24,18 @@ CHECK_DOC_extra714='https://docs.aws.amazon.com/AmazonCloudFront/latest/Develope CHECK_CAF_EPIC_extra714='Logging and Monitoring' extra714(){ - # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if CloudFront distributions have logging enabled " 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 - textPass "CloudFront distribution $dist has logging enabled" + textPass "$REGION: CloudFront distribution $dist has logging enabled" "$REGION" "$dist" else - textFail "CloudFront distribution $dist has logging disabled" + textFail "$REGION: CloudFront distribution $dist has logging disabled" "$REGION" "$dist" fi done else - textInfo "No CloudFront distributions found" + textInfo "$REGION: No CloudFront distributions found" "$REGION" "$dist" fi } diff --git a/checks/check_extra7140 b/checks/check_extra7140 new file mode 100644 index 00000000..4b34c7a5 --- /dev/null +++ b/checks/check_extra7140 @@ -0,0 +1,41 @@ +#!/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_extra7140="7.140" +CHECK_TITLE_extra7140="[extra7140] Check if there are SSM Documents set as public" +CHECK_SCORED_extra7140="NOT_SCORED" +CHECK_TYPE_extra7140="EXTRA" +CHECK_SEVERITY_extra7140="High" +CHECK_ASFF_RESOURCE_TYPE_extra7140="AwsSsmDocument" +CHECK_ALTERNATE_check7140="extra7140" +CHECK_SERVICENAME_extra7140="ssm" +CHECK_RISK_extra7140='SSM Documents may contain private information or even secrets and tokens.' +CHECK_REMEDIATION_extra7140='Carefully review the contents of the document before is shared. Enable SSM Block public sharing for documents.' +CHECK_DOC_extra7140='https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-before-you-share.html' +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) + 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) + if [[ $SSM_DOC_SHARED_ALL ]];then + textFail "$regx: SSM Document $ssmdoc is public." "$regx" "$ssmdoc" + else + textPass "$regx: SSM Document $ssmdoc is not public." "$regx" "$ssmdoc" + fi + done + else + textInfo "$regx: No SSM Document found." "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7141 b/checks/check_extra7141 new file mode 100644 index 00000000..ff4ce69c --- /dev/null +++ b/checks/check_extra7141 @@ -0,0 +1,55 @@ +#!/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_extra7141="7.141" +CHECK_TITLE_extra7141="[extra7141] Find secrets in SSM Documents" +CHECK_SCORED_extra7141="NOT_SCORED" +CHECK_TYPE_extra7141="EXTRA" +CHECK_SEVERITY_extra7141="Critical" +CHECK_ASFF_RESOURCE_TYPE_extra7141="AwsSsmDocument" +CHECK_ALTERNATE_check7141="extra7141" +CHECK_SERVICENAME_extra7141="ssm" +CHECK_RISK_extra7141='Secrets hardcoded into SSM Documents by malware and bad actors to gain lateral access to other services.' +CHECK_REMEDIATION_extra7141='Implement automated detective control (e.g. using tools like Prowler) to scan accounts for passwords and secrets. Use Secrets Manager service to store and retrieve passwords and secrets.' +CHECK_DOC_extra7141='https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-secretsmanager-secret-generatesecretstring.html' +CHECK_CAF_EPIC_extra7141='IAM' + +extra7141(){ + SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM" + if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then + # this folder is deleted once this check is finished + mkdir $SECRETS_TEMP_FOLDER + fi + + for regx in $REGIONS; do + SSM_DOCS=$($AWSCLI $PROFILE_OPT --region $regx ssm list-documents --filters Key=Owner,Values=Self --query DocumentIdentifiers[].Name --output text) + if [[ $SSM_DOCS ]];then + for ssmdoc in $SSM_DOCS; do + SSM_DOC_FILE="$SECRETS_TEMP_FOLDER/extra7141-$ssmdoc-$regx-content.txt" + $AWSCLI $PROFILE_OPT --region $regx ssm get-document --name $ssmdoc --output text --document-format JSON > $SSM_DOC_FILE + FINDINGS=$(secretsDetector file $SSM_DOC_FILE) + if [[ $FINDINGS -eq 0 ]]; then + textPass "$regx: No secrets found in SSM Document $ssmdoc" "$regx" "$ssmdoc" + # delete file if nothing interesting is there + rm -f $SSM_DOC_FILE + else + textFail "$regx: Potential secret found SSM Document $ssmdoc" "$regx" "$ssmdoc" + # delete file to not leave trace, user must look at the CFN Stack + rm -f $SSM_DOC_FILE + fi + done + else + textInfo "$regx: No SSM Document found." "$regx" + fi + done + rm -rf $SECRETS_TEMP_FOLDER +} diff --git a/checks/check_extra7142 b/checks/check_extra7142 new file mode 100644 index 00000000..5fbd6922 --- /dev/null +++ b/checks/check_extra7142 @@ -0,0 +1,44 @@ +#!/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_extra7142="7.142" +CHECK_TITLE_extra7142="[extra7142] Check if Application Load Balancer is dropping invalid packets to prevent header based http request smuggling" +CHECK_SCORED_extra7142="NOT_SCORED" +CHECK_TYPE_extra7142="EXTRA" +CHECK_SEVERITY_extra7142="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7142="AwsElasticLoadBalancingV2LoadBalancer" +CHECK_ALTERNATE_check7142="extra7142" +CHECK_ASFF_COMPLIANCE_TYPE_extra7142="" +CHECK_SERVICENAME_extra7142="elb" +CHECK_RISK_extra7142='ALB can be target of actors sendingn bad http headers' +CHECK_REMEDIATION_extra7142='Ensure Application Load Balancer is configured for HTTP headers with header fields that are not valid are removed by the load balancer (true)' +CHECK_DOC_extra7142='https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#desync-mitigation-mode' +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) + 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) + if [[ $CHECK_IF_DROP_INVALID_HEADER_FIELDS ]];then + textPass "$regx: Application Load Balancer $alb is dropping invalid header fields." "$regx" "$alb" + else + textFail "$regx: Application Load Balancer $alb is not dropping invalid header fields" "$regx" "$alb" + fi + done + else + textInfo "$regx: no ALBs found" + fi + done +} diff --git a/checks/check_extra7143 b/checks/check_extra7143 new file mode 100644 index 00000000..09f24131 --- /dev/null +++ b/checks/check_extra7143 @@ -0,0 +1,49 @@ +#!/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_extra7143="7.143" +CHECK_TITLE_extra7143="[extra7143] Check if EFS have policies which allow access to everyone" +CHECK_SCORED_extra7143="NOT_SCORED" +CHECK_TYPE_extra7143="EXTRA" +CHECK_SEVERITY_extra7143="Critical" +CHECK_ASFF_RESOURCE_TYPE_extra7143="AwsEFS" +CHECK_ALTERNATE_check7143="extra7143" +CHECK_SERVICENAME_extra7143="efs" +CHECK_RISK_extra7143='EFS accessible to everyone could expose sensible data to bad actors' +CHECK_REMEDIATION_extra7143='Ensure efs has some policy but it does not have principle as *' +CHECK_DOC_extra7143='https://docs.aws.amazon.com/efs/latest/ug/access-control-block-public-access.html' +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) + 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) + if [[ $EFS_POLICY_STATEMENTS == *PolicyNotFound* ]]; then + textFail "$regx: EFS: $efsId doesn't have any policy which means it grants full access to any client" "$regx" "$efsId" + else + EFS_POLICY_BAD_STATEMENTS=$(echo $EFS_POLICY_STATEMENTS | jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*")') + if [[ $EFS_POLICY_BAD_STATEMENTS != "" ]]; then + textFail "$regx: EFS $efsId has policy which allows access to everyone" "$regx" "$efsId" + else + textPass "$regx: EFS $efsId has policy which does not allow access to everyone" "$regx" "$efsId" + fi + fi + done + + else + textInfo "$regx: No EFS found" "$regx" + fi + done +} diff --git a/checks/check_extra7144 b/checks/check_extra7144 new file mode 100644 index 00000000..5fc9a270 --- /dev/null +++ b/checks/check_extra7144 @@ -0,0 +1,35 @@ +#!/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_extra7144="7.144" +CHECK_TITLE_extra7144="[extra7144] Check if CloudWatch has allowed cross-account sharing" +CHECK_SCORED_extra7144="NOT_SCORED" +CHECK_TYPE_extra7144="EXTRA" +CHECK_SEVERITY_extra7144="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7144="AwsCloudWatch" +CHECK_ALTERNATE_check7144="extra7144" +CHECK_SERVICENAME_extra7144="cloudwatch" +CHECK_RISK_extra7144='' +CHECK_REMEDIATION_extra7144='' +CHECK_DOC_extra7144='https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Cross-Account-Cross-Region.html' +CHECK_CAF_EPIC_extra7144='Logging and Monitoring' + +extra7144(){ + # "Check if aws cloudwatch has allowed sharing with other accounts (Not Scored) (Not part of CIS benchmark)" + CLOUDWATCH_CROSS_ACCOUNT_ROLE=$($AWSCLI iam get-role $PROFILE_OPT --role-name=CloudWatch-CrossAccountSharingRole --output json --query Role 2>&1) + if [[ $CLOUDWATCH_CROSS_ACCOUNT_ROLE != *NoSuchEntity* ]]; then + CLOUDWATCH_POLICY_BAD_STATEMENTS=$(echo $CLOUDWATCH_CROSS_ACCOUNT_ROLE | jq '.AssumeRolePolicyDocument') + textInfo "$REGION: CloudWatch has allowed cross-account sharing" "$REGION" + else + textPass "$REGION: CloudWatch doesn't allows cross-account sharing" "$REGION" + fi +} diff --git a/checks/check_extra7145 b/checks/check_extra7145 new file mode 100644 index 00000000..fa74b27b --- /dev/null +++ b/checks/check_extra7145 @@ -0,0 +1,49 @@ +#!/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_extra7145="7.145" +CHECK_TITLE_extra7145="[extra7145] Check if Lambda functions have policies which allow access to any AWS account" +CHECK_SCORED_extra7145="NOT_SCORED" +CHECK_TYPE_extra7145="EXTRA" +CHECK_SEVERITY_extra7145="Critical" +CHECK_ASFF_RESOURCE_TYPE_extra7145="AwsLambda" +CHECK_ALTERNATE_check7145="extra7145" +CHECK_SERVICENAME_extra7145="lambda" +CHECK_RISK_extra7145='Lambda function access to any AWS account may result security issues' +CHECK_REMEDIATION_extra7145='Ensure Lambda function policiy does not allow access to any account' +CHECK_DOC_extra7145='https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html' +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) + 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) + if [[ $FUNCTION_POLICY_STATEMENTS == *ResourceNotFoundException* ]]; then + textInfo "$regx: Lambda function $lambdaFunction doesn't have any policy" "$regx" "$lambdaFunction" + else + FUNCTION_POLICY_BAD_STATEMENTS=$(echo $FUNCTION_POLICY_STATEMENTS | jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*")') + if [[ $FUNCTION_POLICY_BAD_STATEMENTS != "" ]]; then + textFail "$regx: Lambda function $lambdaFunction allows public access to any AWS account" "$regx" "$lambdaFunction" + else + textPass "$regx: Lambda function $lambdaFunction has policy which doesn't allow access to everyone having an AWS account" "$regx" "$lambdaFunction" + fi + fi + done + + else + textInfo "$regx: No lambda functions found" "$regx" + fi + done +} diff --git a/checks/check_extra7146 b/checks/check_extra7146 new file mode 100644 index 00000000..92ffb813 --- /dev/null +++ b/checks/check_extra7146 @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +CHECK_ID_extra7146="7.146" +CHECK_TITLE_extra7146="[extra7146] Check if there is any unassigned Elastic IP" +CHECK_SCORED_extra7146="NOT_SCORED" +CHECK_TYPE_extra7146="EXTRA" +CHECK_SEVERITY_extra7146="Low" +CHECK_ASFF_RESOURCE_TYPE_extra7146="AwsElasticIPs" +CHECK_ALTERNATE_check7146="extra7146" +CHECK_SERVICENAME_extra7146="ec2" +CHECK_RISK_extra7146='Unassigned Elastic IPs may result in extra cost' +CHECK_REMEDIATION_extra7146='Ensure Elastic IPs are not unassigned' +CHECK_DOC_extra7146='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html' +CHECK_CAF_EPIC_extra7146='Infrastructure Security' + +extra7146(){ + # "Check if there is any unassigned elastic ip (Not Scored) (Not part of CIS benchmark)" + for regx in $REGIONS; do + ELASTIC_IP_ADDRESSES=$($AWSCLI ec2 describe-addresses $PROFILE_OPT --region $regx --query Addresses --output json) + if [[ $ELASTIC_IP_ADDRESSES != [] ]]; then + LIST_OF_ASSOCIATED_IPS=$(echo $ELASTIC_IP_ADDRESSES | jq -r '.[] | select(.AssociationId!=null) | .PublicIp') + LIST_OF_UNASSOCIATED_IPS=$(echo $ELASTIC_IP_ADDRESSES | jq -r '.[] | select(.AssociationId==null) | .PublicIp') + for ass_ip in $LIST_OF_ASSOCIATED_IPS; do + textPass "$regx: Elastic IP $ass_ip is associated with an instance or network interface" "$regx" "$ass_ip" + done + for unass_ip in $LIST_OF_UNASSOCIATED_IPS; do + textInfo "$regx: Elastic IP $unass_ip is not associated with any instance or network interface and it may incurr extra cost" "$regx" "$unass_ip" + done + else + textInfo "$regx: No Elastic IPs found" "$regx" + fi + done +} diff --git a/checks/check_extra7147 b/checks/check_extra7147 new file mode 100644 index 00000000..cff62c59 --- /dev/null +++ b/checks/check_extra7147 @@ -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_extra7147="7.147" +CHECK_TITLE_extra7147="[extra7147] Check if S3 Glacier vaults have policies which allow access to everyone" +CHECK_SCORED_extra7147="NOT_SCORED" +CHECK_TYPE_extra7147="EXTRA" +CHECK_SEVERITY_extra7147="Critical" +CHECK_ASFF_RESOURCE_TYPE_extra7147="AwsGlacierVault" +CHECK_ALTERNATE_check7147="extra7142" +CHECK_SERVICENAME_extra7147="glacier" +CHECK_RISK_extra7147='Vaults accessible to everyone could expose sensible data to bad actors' +CHECK_REMEDIATION_extra7147='Ensure vault policy does not have principle as *' +CHECK_DOC_extra7147='https://docs.aws.amazon.com/amazonglacier/latest/dev/access-control-overview.html' +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) + 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) + if [[ $VAULT_POLICY_STATEMENTS == *GetVaultAccessPolicy* ]]; then + textInfo "$regx: Vault $vault doesn't have any policy" "$regx" "$vault" + else + VAULT_POLICY_BAD_STATEMENTS=$(echo $VAULT_POLICY_STATEMENTS | jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*")') + if [[ $VAULT_POLICY_BAD_STATEMENTS != "" ]]; then + textFail "$regx: Vault $vault has policy which allows access to everyone" "$regx" "$vault" + else + textPass "$regx: Vault $vault has policy which does not allow access to everyone" "$regx" "$vault" + fi + fi + done + else + textInfo "$regx: No Glacier vaults found" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra715 b/checks/check_extra715 index 2be3409b..2ce8d287 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -30,15 +30,15 @@ extra715(){ 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) if [[ $SEARCH_SLOWLOG_ENABLED ]];then - textPass "$regx: Amazon ES domain $domain SEARCH_SLOW_LOGS enabled" "$regx" + textPass "$regx: Amazon ES domain $domain SEARCH_SLOW_LOGS enabled" "$regx" "$domain" else - textFail "$regx: Amazon ES domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" + textFail "$regx: Amazon ES domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" "$domain" fi INDEX_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.INDEX_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) if [[ $INDEX_SLOWLOG_ENABLED ]];then - textPass "$regx: Amazon ES domain $domain INDEX_SLOW_LOGS enabled" "$regx" + textPass "$regx: Amazon ES domain $domain INDEX_SLOW_LOGS enabled" "$regx" "$domain" else - textFail "$regx: Amazon ES domain $domain INDEX_SLOW_LOGS disabled!" "$regx" + textFail "$regx: Amazon ES domain $domain INDEX_SLOW_LOGS disabled!" "$regx" "$domain" fi done else diff --git a/checks/check_extra716 b/checks/check_extra716 index 360d32f2..9a307f67 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -34,13 +34,13 @@ extra716(){ # If the endpoint starts with "vpc-" it is in a VPC then it is fine. if [[ "$ES_DOMAIN_ENDPOINT" =~ ^vpc-* ]];then ES_DOMAIN_VPC=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.VPCOptions.VPCId' --output text) - textInfo "$regx: Amazon ES domain $domain is in VPC $ES_DOMAIN_VPC run extra779 to make sure it is not exposed using custom proxy" "$regx" + textInfo "$regx: Amazon ES domain $domain is in VPC $ES_DOMAIN_VPC run extra779 to make sure it is not exposed using custom proxy" "$regx" "$domain" else $AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.AccessPolicies.Options --output text > $TEMP_POLICY_FILE 2> /dev/null # check if the policy has a principal set up CHECK_ES_POLICY_PRINCIPAL=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS != "*") or ((.Principal|type == "string") and .Principal != "*")) and select(has("Condition") | not))') if [[ $CHECK_ES_POLICY_PRINCIPAL ]]; then - textPass "$regx: Amazon ES domain $domain does have a Principal set up" "$regx" + textPass "$regx: Amazon ES domain $domain does have a Principal set up" "$regx" "$domain" fi CHECK_ES_DOMAIN_POLICY_OPEN=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition") | not))') CHECK_ES_DOMAIN_POLICY_HAS_CONDITION=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition")))' ) @@ -67,22 +67,22 @@ extra716(){ fi if [[ $CHECK_ES_DOMAIN_POLICY_OPEN || $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO || $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR || ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then if [[ $CHECK_ES_DOMAIN_POLICY_OPEN ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\") - use extra788 to test AUTH" "$regx" + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\") - use extra788 to test AUTH" "$regx" "$domain" fi if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network 0.0.0.0) - use extra788 to test AUTH" "$regx" + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network 0.0.0.0) - use extra788 to test AUTH" "$regx" "$domain" fi if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR ]];then - textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") - use extra788 to test AUTH" "$regx" + textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") - use extra788 to test AUTH" "$regx" "$domain" fi if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then - textInfo "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and Public IP or Network $(echo ${CONDITION_HAS_PUBLIC_IP_ARRAY[@]})) - use extra788 to test AUTH" "$regx" + textInfo "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and Public IP or Network $(echo ${CONDITION_HAS_PUBLIC_IP_ARRAY[@]})) - use extra788 to test AUTH" "$regx" "$domain" fi else if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PRIVATE_IP[@]} ]];then - textInfo "$regx: Amazon ES domain $domain policy allows access from a Private IP or CIDR RFC1918 $(echo ${CONDITION_HAS_PRIVATE_IP_ARRAY[@]})" "$regx" + textInfo "$regx: Amazon ES domain $domain policy allows access from a Private IP or CIDR RFC1918 $(echo ${CONDITION_HAS_PRIVATE_IP_ARRAY[@]})" "$regx" "$domain" else - textPass "$regx: Amazon ES domain $domain does not allow anonymous access" "$regx" + textPass "$regx: Amazon ES domain $domain does not allow anonymous access" "$regx" "$domain" fi fi rm -f $TEMP_POLICY_FILE diff --git a/checks/check_extra717 b/checks/check_extra717 index 982bb232..f2f8996c 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra717="7.17" -CHECK_TITLE_extra717="[extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra717="[extra717] Check if Elastic Load Balancers have logging enabled" CHECK_SCORED_extra717="NOT_SCORED" CHECK_TYPE_extra717="EXTRA" CHECK_SEVERITY_extra717="Medium" @@ -24,7 +24,7 @@ CHECK_DOC_extra717='https://docs.aws.amazon.com/elasticloadbalancing/latest/appl CHECK_CAF_EPIC_extra717='Logging and Monitoring' extra717(){ - # "Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" + # "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) @@ -33,9 +33,9 @@ extra717(){ 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") if [[ $CHECK_ELBS_LOG_ENABLED ]]; then - textPass "$regx: $elb has access logs to S3 configured" "$regx" + textPass "$regx: $elb has access logs to S3 configured" "$regx" "$elb" else - textFail "$regx: $elb has not configured access logs" "$regx" + textFail "$regx: $elb has not configured access logs" "$regx" "$elb" fi done fi @@ -44,9 +44,9 @@ extra717(){ 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" + textPass "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" "$elb" else - textFail "$regx: $ELBV2_NAME has not configured access logs" "$regx" + textFail "$regx: $ELBV2_NAME has not configured access logs" "$regx" "$elb" fi done fi diff --git a/checks/check_extra718 b/checks/check_extra718 index 39f27bb1..8e1e8020 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra718="7.18" -CHECK_TITLE_extra718="[extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra718="[extra718] Check if S3 buckets have server access logging enabled" CHECK_SCORED_extra718="NOT_SCORED" CHECK_TYPE_extra718="EXTRA" CHECK_SEVERITY_extra718="Medium" @@ -24,22 +24,22 @@ CHECK_DOC_extra718='https://docs.aws.amazon.com/AmazonS3/latest/dev/security-bes CHECK_CAF_EPIC_extra718='Logging and Monitoring' extra718(){ - # "Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if S3 buckets have server access logging enabled " LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text 2>&1) if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep AccessDenied) ]]; then - textFail "Access Denied Trying to Get Bucket Logging for $bucket" + textFail "$REGION: Access Denied Trying to Get Bucket Logging for $bucket" "$REGION" "$bucket" continue fi if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep "^None$") ]]; then - textFail "Bucket $bucket has server access logging disabled!" + textFail "$REGION: Bucket $bucket has server access logging disabled!" "$REGION" "$bucket" else - textPass "Bucket $bucket has server access logging enabled" + textPass "$REGION: Bucket $bucket has server access logging enabled" "$REGION" "$bucket" fi done else - textInfo "No S3 Buckets found" + textInfo "$REGION: No S3 Buckets found" "$REGION" "$bucket" fi } diff --git a/checks/check_extra719 b/checks/check_extra719 index 998c6e86..b3435656 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra719="7.19" -CHECK_TITLE_extra719="[extra719] Check if Route53 public hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra719="[extra719] Check if Route53 public hosted zones are logging queries to CloudWatch Logs" CHECK_SCORED_extra719="NOT_SCORED" CHECK_TYPE_extra719="EXTRA" CHECK_SEVERITY_extra719="Medium" @@ -30,12 +30,12 @@ extra719(){ for hostedzoneid in $LIST_OF_HOSTED_ZONES;do HOSTED_ZONE_QUERY_LOG_ENABLED=$($AWSCLI route53 list-query-logging-configs --hosted-zone-id $hostedzoneid $PROFILE_OPT --query QueryLoggingConfigs[*].CloudWatchLogsLogGroupArn --output text|cut -d: -f7) if [[ $HOSTED_ZONE_QUERY_LOG_ENABLED ]];then - textPass "Route53 public hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" + textPass "$REGION: Route53 public hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" "$REGION" "$hostedzoneid" else - textFail "Route53 public hosted zone Id $hostedzoneid has query logging disabled!" + textFail "$REGION: Route53 public hosted zone Id $hostedzoneid has query logging disabled!" "$REGION" "$hostedzoneid" fi done else - textInfo "No Route53 hosted zones found" + textInfo "$REGION: No Route53 hosted zones found" "$REGION" fi } diff --git a/checks/check_extra72 b/checks/check_extra72 index b4ce5a70..0d088896 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra72="7.2" -CHECK_TITLE_extra72="[extra72] Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra72="[extra72] Ensure there are no EBS Snapshots set as Public" CHECK_SCORED_extra72="NOT_SCORED" CHECK_TYPE_extra72="EXTRA" CHECK_SEVERITY_extra72="Critical" @@ -26,16 +26,15 @@ CHECK_DOC_extra72='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-modif CHECK_CAF_EPIC_extra72='Data Protection' extra72(){ - # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for EBS Snapshots in all regions... " + # "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) 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 - textFail "$regx: $snapshot is currently Public!" "$regx" + textFail "$regx: $snapshot is currently Public!" "$regx" "$snapshot" else - textPass "$regx: $snapshot is not Public" "$regx" + textPass "$regx: $snapshot is not Public" "$regx" "$snapshot" fi done done diff --git a/checks/check_extra720 b/checks/check_extra720 index 396f59b2..06608532 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra720="7.20" -CHECK_TITLE_extra720="[extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra720="[extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail" CHECK_SCORED_extra720="NOT_SCORED" CHECK_TYPE_extra720="EXTRA" CHECK_SEVERITY_extra720="Low" @@ -24,17 +24,17 @@ CHECK_DOC_extra720='https://docs.aws.amazon.com/lambda/latest/dg/logging-using-c CHECK_CAF_EPIC_extra720='Logging and Monitoring' extra720(){ - # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" + # "Check if Lambda functions invoke API operations are being recorded by CloudTrail " 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" + textFail "$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" + textFail "$regx: Access Denied trying to describe trails" "$regx" continue fi for lambdafunction in $LIST_OF_FUNCTIONS; do @@ -42,9 +42,9 @@ extra720(){ for trail in $LIST_OF_TRAILS; do FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:${AWS_PARTITION}:lambda.*function:$lambdafunction$|^arn:${AWS_PARTITION}:lambda$") if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then - textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" + textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" "$trail" else - textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" + textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" "$trail" fi done # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) @@ -62,7 +62,7 @@ extra720(){ # textFail "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" # fi else - textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" + textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" "$trail" fi done else diff --git a/checks/check_extra721 b/checks/check_extra721 index d8c03776..8b2e54bf 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra721="7.21" -CHECK_TITLE_extra721="[extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra721="[extra721] Check if Redshift cluster has audit logging enabled" CHECK_SCORED_extra721="NOT_SCORED" CHECK_TYPE_extra721="EXTRA" CHECK_SEVERITY_extra721="Medium" @@ -24,7 +24,7 @@ CHECK_DOC_extra721='https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing CHECK_CAF_EPIC_extra721='Logging and Monitoring' extra721(){ - # "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" + # "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) if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then @@ -32,9 +32,9 @@ extra721(){ REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True) if [[ $REDSHIFT_LOG_ENABLED ]];then REDSHIFT_LOG_ENABLED_BUCKET=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query BucketName --output text) - textPass "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" + textPass "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" "$redshiftcluster" else - textFail "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" + textFail "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" "$redshiftcluster" fi done else diff --git a/checks/check_extra722 b/checks/check_extra722 index 30146620..4db8470c 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra722="7.22" -CHECK_TITLE_extra722="[extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra722="[extra722] Check if API Gateway has logging enabled" CHECK_SCORED_extra722="NOT_SCORED" CHECK_TYPE_extra722="EXTRA" CHECK_SEVERITY_extra722="Medium" @@ -24,7 +24,7 @@ CHECK_DOC_extra722='https://docs.aws.amazon.com/apigateway/latest/developerguide CHECK_CAF_EPIC_extra722='Logging and Monitoring' extra722(){ - # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" + # "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) if [[ $LIST_OF_API_GW ]];then @@ -35,13 +35,13 @@ extra722(){ for stagname in $CHECK_STAGES_NAME;do CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[?stageName == \`$stagname\` ].methodSettings" --output text |awk '{ print $6 }' |egrep 'ERROR|INFO') if [[ $CHECK_STAGE_METHOD_LOGGING ]];then - textPass "$regx: API Gateway $API_GW_NAME ID $apigwid in $stagname has logging enabled as $CHECK_STAGE_METHOD_LOGGING" "$regx" + textPass "$regx: API Gateway $API_GW_NAME ID $apigwid in $stagname has logging enabled as $CHECK_STAGE_METHOD_LOGGING" "$regx" "$API_GW_NAME" else - textFail "$regx: API Gateway $API_GW_NAME ID $apigwid in $stagname has logging disabled" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $apigwid in $stagname has logging disabled" "$regx" "$API_GW_NAME" fi done else - textFail "$regx: No Stage name found for $API_GW_NAME" "$regx" + textFail "$regx: No Stage name found for $API_GW_NAME" "$regx" "$API_GW_NAME" fi done else diff --git a/checks/check_extra723 b/checks/check_extra723 index 187f50ce..9653b956 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra723="7.23" -CHECK_TITLE_extra723="[extra723] Check if RDS Snapshots and Cluster Snapshots are public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra723="[extra723] Check if RDS Snapshots and Cluster Snapshots are public" CHECK_SCORED_extra723="NOT_SCORED" CHECK_TYPE_extra723="EXTRA" CHECK_SEVERITY_extra723="Critical" @@ -24,7 +24,7 @@ CHECK_DOC_extra723='https://docs.aws.amazon.com/config/latest/developerguide/rds CHECK_CAF_EPIC_extra723='Data Protection' extra723(){ - # "Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" + # "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) @@ -32,13 +32,13 @@ extra723(){ 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) if [[ $SNAPSHOT_IS_PUBLIC ]];then - textFail "$regx: RDS Snapshot $rdssnapshot is public!" "$regx" + textFail "$regx: RDS Snapshot $rdssnapshot is public!" "$regx" "$rdssnapshot" else - textPass "$regx: RDS Snapshot $rdssnapshot is not shared" "$regx" + textPass "$regx: RDS Snapshot $rdssnapshot is not shared" "$regx" "$rdssnapshot" fi done else - textInfo "$regx: No RDS Snapshots found" "$regx" + textInfo "$regx: No RDS Snapshots found" "$regx" "$rdssnapshot" fi # RDS cluster snapshots LIST_OF_RDS_CLUSTER_SNAPSHOTS=$($AWSCLI rds describe-db-cluster-snapshots $PROFILE_OPT --region $regx --query DBClusterSnapshots[*].DBClusterSnapshotIdentifier --output text) @@ -46,13 +46,13 @@ extra723(){ for rdsclustersnapshot in $LIST_OF_RDS_CLUSTER_SNAPSHOTS;do CLUSTER_SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-cluster-snapshot-attributes $PROFILE_OPT --region $regx --db-cluster-snapshot-identifier $rdsclustersnapshot --query DBClusterSnapshotAttributesResult.DBClusterSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) if [[ $CLUSTER_SNAPSHOT_IS_PUBLIC ]];then - textFail "$regx: RDS Cluster Snapshot $rdsclustersnapshot is public!" "$regx" + textFail "$regx: RDS Cluster Snapshot $rdsclustersnapshot is public!" "$regx" "$rdsclustersnapshot" else - textPass "$regx: RDS Cluster Snapshot $rdsclustersnapshot is not shared" "$regx" + textPass "$regx: RDS Cluster Snapshot $rdsclustersnapshot is not shared" "$regx" "$rdsclustersnapshot" fi done else - textInfo "$regx: No RDS Cluster Snapshots found" "$regx" + textInfo "$regx: No RDS Cluster Snapshots found" "$regx" "$rdsclustersnapshot" fi done } diff --git a/checks/check_extra724 b/checks/check_extra724 index 69356973..e0b2497f 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra724="7.24" -CHECK_TITLE_extra724="[extra724] Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra724="[extra724] Check if ACM certificates have Certificate Transparency logging enabled" CHECK_SCORED_extra724="NOT_SCORED" CHECK_TYPE_extra724="EXTRA" CHECK_SEVERITY_extra724="Medium" @@ -24,7 +24,7 @@ CHECK_DOC_extra724='https://aws.amazon.com/blogs/security/how-to-get-ready-for-c CHECK_CAF_EPIC_extra724='Logging and Monitoring' extra724(){ - # "Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if ACM certificates have Certificate Transparency logging enabled " for regx in $REGIONS; do LIST_OF_CERTS=$($AWSCLI acm list-certificates $PROFILE_OPT --region $regx --query CertificateSummaryList[].CertificateArn --output text) if [[ $LIST_OF_CERTS ]];then @@ -34,12 +34,12 @@ extra724(){ CERT_TYPE=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Type --output text) if [[ $CERT_TYPE == "IMPORTED" ]];then # Ignore imported certificate - textInfo "$regx: ACM Certificate $CERT_DOMAIN_NAME is imported." "$regx" + textInfo "$regx: ACM Certificate $CERT_DOMAIN_NAME is imported." "$regx" "$CERT_DOMAIN_NAME" else if [[ $CT_ENABLED == "ENABLED" ]];then - textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" + textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" "$CERT_DOMAIN_NAME" else - textFail "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" + textFail "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" "$CERT_DOMAIN_NAME" fi fi done @@ -47,5 +47,4 @@ extra724(){ textInfo "$regx: No ACM Certificates found" "$regx" fi done - textInfo "*Read more about this here: https://aws.amazon.com/blogs/security/how-to-get-ready-for-certificate-transparency/" } diff --git a/checks/check_extra725 b/checks/check_extra725 index 614feff0..4100b083 100644 --- a/checks/check_extra725 +++ b/checks/check_extra725 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra725="7.25" -CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled in CloudTrail" CHECK_SCORED_extra725="NOT_SCORED" CHECK_TYPE_extra725="EXTRA" CHECK_SEVERITY_extra725="Medium" @@ -26,17 +26,15 @@ CHECK_CAF_EPIC_extra725='Logging and Monitoring' # per Object-level logging is not configured at Bucket level but at CloudTrail trail level extra725(){ - # "Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for S3 Buckets Object-level logging information in all trails... " - + # "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 "Access Denied trying to list buckets" + textFail "$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 "Access Denied trying to describe trails" + textFail "$REGION: Access Denied trying to describe trails" return fi if [[ $LIST_OF_BUCKETS ]]; then @@ -53,17 +51,17 @@ extra725(){ if [[ ${#BUCKET_ENABLED_TRAILS[@]} -gt 0 ]]; then for trail in "${BUCKET_ENABLED_TRAILS[@]}"; do - textPass "$regx: S3 bucket $bucketName has Object-level logging enabled in trail $trail" "$regx" + textPass "$REGION: S3 bucket $bucketName has Object-level logging enabled in trail $trail" "$REGION" "$bucketName" done else - textFail "$regx: S3 bucket $bucketName has Object-level logging disabled" "$regx" + textFail "$REGION: S3 bucket $bucketName has Object-level logging disabled" "$REGION" "$bucketName" fi else - textFail "$regx: S3 bucket $bucketName is not being recorded no CloudTrail found!" "$regx" + textFail "$REGION: S3 bucket $bucketName is not being recorded no CloudTrail found!" "$REGION" "$bucketName" fi done else - textInfo "$regx: No S3 buckets found" "$regx" + textInfo "$REGION: No S3 buckets found" "$REGION" fi } diff --git a/checks/check_extra726 b/checks/check_extra726 index 341833e1..76de3c84 100644 --- a/checks/check_extra726 +++ b/checks/check_extra726 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra726="7.26" -CHECK_TITLE_extra726="[extra726] Check Trusted Advisor for errors and warnings (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra726="[extra726] Check Trusted Advisor for errors and warnings" CHECK_SCORED_extra726="NOT_SCORED" CHECK_TYPE_extra726="EXTRA" CHECK_SEVERITY_extra726="Medium" @@ -25,32 +25,32 @@ CHECK_CAF_EPIC_extra726='IAM' extra726(){ trap "exit" INT - # forcing us-east-1 region only since support only works in that region - TA_CHECKS_ID=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query checks[*].id --output text 2>&1) + # forcing REGION if not set will be us-east-1 region only since support only works in that region + TA_CHECKS_ID=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region $REGION --query checks[*].id --output text 2>&1) if [[ $(echo "$TA_CHECKS_ID" | grep SubscriptionRequiredException) ]]; then - textInfo "Trusted Advisor requires AWS Premium Support Subscription" + textInfo "$REGION: Trusted Advisor requires AWS Premium Support Subscription" "$REGION" return fi for checkid in $TA_CHECKS_ID; do - TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text) - QUERY_TA_CHECK_RESULT=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text) + TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region $REGION --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text) + QUERY_TA_CHECK_RESULT=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region $REGION --query 'result.status' --output text) # 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 "Trusted Advisor check $TA_CHECKS_NAME is in ok state $QUERY_TA_CHECK_RESULT" + textPass "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in ok state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "error") - textFail "Trusted Advisor check $TA_CHECKS_NAME is in error state $QUERY_TA_CHECK_RESULT" + textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in error state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "warning") - textInfo "Trusted Advisor check $TA_CHECKS_NAME is in warning state $QUERY_TA_CHECK_RESULT" + textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in warning state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; "not_available") - textInfo "Trusted Advisor check $TA_CHECKS_NAME is in not_available state $QUERY_TA_CHECK_RESULT" + textInfo "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in not_available state $QUERY_TA_CHECK_RESULT" "u$REGION" "$TA_CHECKS_NAME" ;; "*") - textFail "Trusted Advisor check $TA_CHECKS_NAME is in unknown state $QUERY_TA_CHECK_RESULT" + textFail "$REGION: Trusted Advisor check $TA_CHECKS_NAME is in unknown state $QUERY_TA_CHECK_RESULT" "$REGION" "$TA_CHECKS_NAME" ;; esac done diff --git a/checks/check_extra727 b/checks/check_extra727 index 400e78d8..797401be 100644 --- a/checks/check_extra727 +++ b/checks/check_extra727 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra727="7.27" -CHECK_TITLE_extra727="[extra727] Check if SQS queues have policy set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra727="[extra727] Check if SQS queues have policy set as Public" CHECK_SCORED_extra727="NOT_SCORED" CHECK_TYPE_extra727="EXTRA" CHECK_SEVERITY_extra727="Critical" @@ -39,15 +39,15 @@ 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" + textFail "$regx: SQS $queue queue policy with public access: $SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS" "$regx" "$queue" else - textInfo "$regx: SQS $queue queue policy with public access but has a Condition" "$regx" + textInfo "$regx: SQS $queue queue policy with public access but has a Condition" "$regx" "$queue" fi else - textPass "$regx: SQS $queue queue without public access" "$regx" + textPass "$regx: SQS $queue queue without public access" "$regx" "$queue" fi else - textPass "$regx: SQS $queue queue without policy" "$regx" + textPass "$regx: SQS $queue queue without policy" "$regx" "$queue" fi done else diff --git a/checks/check_extra728 b/checks/check_extra728 index 60758fd1..f7589af1 100644 --- a/checks/check_extra728 +++ b/checks/check_extra728 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra728="7.28" -CHECK_TITLE_extra728="[extra728] Check if SQS queues have Server Side Encryption enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra728="[extra728] Check if SQS queues have Server Side Encryption enabled" CHECK_SCORED_extra728="NOT_SCORED" CHECK_TYPE_extra728="EXTRA" CHECK_SEVERITY_extra728="Medium" @@ -33,9 +33,9 @@ extra728(){ # check if the policy has KmsMasterKeyId therefore SSE enabled SSE_ENABLED_QUEUE=$($AWSCLI sqs get-queue-attributes --queue-url $queue $PROFILE_OPT --region $regx --attribute-names All --query Attributes.KmsMasterKeyId --output text|grep -v ^None) if [[ $SSE_ENABLED_QUEUE ]]; then - textPass "$regx: SQS queue $queue is using Server Side Encryption" "$regx" + textPass "$regx: SQS queue $queue is using Server Side Encryption" "$regx" "$queue" else - textFail "$regx: SQS queue $queue is not using Server Side Encryption" "$regx" + textFail "$regx: SQS queue $queue is not using Server Side Encryption" "$regx" "$queue" fi done else diff --git a/checks/check_extra729 b/checks/check_extra729 index 21feea47..743e568d 100644 --- a/checks/check_extra729 +++ b/checks/check_extra729 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra729="7.29" -CHECK_TITLE_extra729="[extra729] Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra729="[extra729] Ensure there are no EBS Volumes unencrypted" CHECK_SCORED_extra729="NOT_SCORED" CHECK_TYPE_extra729="EXTRA" CHECK_SEVERITY_extra729="Medium" @@ -26,19 +26,18 @@ CHECK_DOC_extra729='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncry CHECK_CAF_EPIC_extra729='Data Protection' extra729(){ - # "Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for EBS Volumes in all regions... " + # "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) 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" + textFail "$regx: $volume is not encrypted!" "$regx" "$volume" done fi LIST_OF_EBS_ENC_VOLUMES=$($AWSCLI ec2 describe-volumes $PROFILE_OPT --region $regx --query 'Volumes[?Encrypted==`true`].VolumeId' --output text) if [[ $LIST_OF_EBS_ENC_VOLUMES ]];then for volume in $LIST_OF_EBS_ENC_VOLUMES; do - textPass "$regx: $volume is encrypted" "$regx" + textPass "$regx: $volume is encrypted" "$regx" "$volume" done fi done diff --git a/checks/check_extra73 b/checks/check_extra73 index 0340096b..c2329607 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra73="7.3" -CHECK_TITLE_extra73="[extra73] Ensure there are no S3 buckets open to Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra73="[extra73] Ensure there are no S3 buckets open to Everyone or Any AWS user" CHECK_SCORED_extra73="NOT_SCORED" CHECK_TYPE_extra73="EXTRA" CHECK_SEVERITY_extra73="Critical" @@ -43,14 +43,12 @@ CHECK_CAF_EPIC_extra73='Data Protection' # for day to day usage that is probably desirable. extra73(){ - textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... " - # # If public ACLs disabled at account level then look no further # 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 "Access Denied getting PublicAccessBlock configuration for AWS account" + textFail "$REGION: Access Denied getting PublicAccessBlock configuration for AWS account" "$REGION" "$bucket" return fi if [[ $(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | grep NoSuchPublicAccessBlockConfiguration) ]]; then @@ -61,7 +59,7 @@ extra73(){ ACCOUNTRESTRICTPUBLICBUCKETS=$(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | jq -r '.PublicAccessBlockConfiguration.RestrictPublicBuckets') fi if [[ $ACCOUNTIGNOREPUBLICACLS == "true" && $ACCOUNTRESTRICTPUBLICBUCKETS == "true" ]]; then - textPass "All S3 public access blocked at account level" + textPass "$REGION: All S3 public access blocked at account level" "$REGION" "$bucket" return fi @@ -70,11 +68,11 @@ 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 "Access Denied Trying to List Buckets" + textFail "$REGION: Access Denied Trying to List Buckets" "$REGION" "$bucket" return fi if [[ "$ALL_BUCKETS_LIST" == "" ]]; then - textInfo "No buckets found" + textInfo "$REGION: No buckets found" "$REGION" "$bucket" return fi @@ -87,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 "Access Denied Trying to Get Bucket Location for $bucket" + textFail "$REGION: Access Denied Trying to Get Bucket Location for $bucket" "$REGION" "$bucket" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -101,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 "Access Denied Trying to Get Public Access Block for $bucket" + textFail "$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 @@ -112,7 +110,7 @@ extra73(){ BUCKETRESTRICTPUBLICBUCKETS=$(echo "$BUCKET_PUBLIC_ACCESS_BLOCK" | jq -r '.PublicAccessBlockConfiguration.RestrictPublicBuckets') fi if [[ $BUCKETIGNOREPUBLICACLS == "true" && $BUCKETRESTRICTPUBLICBUCKETS == "true" ]]; then - textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION" + textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION" "$bucket" continue fi @@ -121,19 +119,19 @@ 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 "Access Denied Trying to Get Bucket Acl for $bucket" + textFail "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Acl for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi ALLUSERS_ACL=$(echo "$BUCKET_ACL" | jq '.Grants[]|select(.Grantee.URI != null)|select(.Grantee.URI | endswith("/AllUsers"))') if [[ $ALLUSERS_ACL != "" ]]; then - textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" + textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" "$bucket" continue fi AUTHENTICATEDUSERS_ACL=$(echo "$BUCKET_ACL" | jq '.Grants[]|select(.Grantee.URI != null)|select(.Grantee.URI | endswith("/AuthenticatedUsers"))') if [[ $AUTHENTICATEDUSERS_ACL != "" ]]; then - textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" + textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" "$bucket" continue fi @@ -142,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 "Access Denied Trying to Get Bucket Policy Status for $bucket" + textFail "$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 @@ -150,11 +148,11 @@ extra73(){ fi if [[ $BUCKET_POLICY_STATUS != "" && $BUCKET_POLICY_STATUS != "False" ]]; then - textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" + textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION" "$bucket" continue fi - textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION" + textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION" "$bucket" done } diff --git a/checks/check_extra730 b/checks/check_extra730 index 100cb37d..706922fa 100644 --- a/checks/check_extra730 +++ b/checks/check_extra730 @@ -14,7 +14,7 @@ DAYS_TO_EXPIRE_THRESHOLD="7" CHECK_ID_extra730="7.30" -CHECK_TITLE_extra730="[extra730] Check if ACM Certificates are about to expire in $DAYS_TO_EXPIRE_THRESHOLD days or less (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra730="[extra730] Check if ACM Certificates are about to expire in $DAYS_TO_EXPIRE_THRESHOLD days or less" CHECK_SCORED_extra730="NOT_SCORED" CHECK_TYPE_extra730="EXTRA" CHECK_SEVERITY_extra730="High" @@ -37,9 +37,9 @@ extra730(){ EXPIRES_DATE=$(timestamp_to_date $NOTAFTER) COUNTER_DAYS=$(how_many_days_from_today $EXPIRES_DATE) if [[ $COUNTER_DAYS -le $DAYS_TO_EXPIRE_THRESHOLD ]]; then - textFail "$regx: Certificate for $FQDN is about to expire in $COUNTER_DAYS days!" "$regx" + textFail "$regx: Certificate for $FQDN is about to expire in $COUNTER_DAYS days!" "$regx" "$FQDN" else - textPass "$regx: Certificate for $FQDN expires in $COUNTER_DAYS days" "$regx" + textPass "$regx: Certificate for $FQDN expires in $COUNTER_DAYS days" "$regx" "$FQDN" fi done done diff --git a/checks/check_extra731 b/checks/check_extra731 index 5bf1743b..3a5eec01 100644 --- a/checks/check_extra731 +++ b/checks/check_extra731 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra731="7.31" -CHECK_TITLE_extra731="[extra731] Check if SNS topics have policy set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra731="[extra731] Check if SNS topics have policy set as Public" CHECK_SCORED_extra731="NOT_SCORED" CHECK_TYPE_extra731="EXTRA" CHECK_SEVERITY_extra731="Critical" @@ -39,9 +39,9 @@ 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" + textFail "$regx: SNS topic $SHORT_TOPIC's policy with public access: $SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION_DETAILS" "$regx" "$SHORT_TOPIC" else - textPass "$regx: SNS topic $SHORT_TOPIC's policy with public access but has a Condition" "$regx" + textPass "$regx: SNS topic $SHORT_TOPIC's policy with public access but has a Condition" "$regx" "$SHORT_TOPIC" fi else textPass "$regx: SNS topic without public access" "$regx" diff --git a/checks/check_extra732 b/checks/check_extra732 index 2f355c13..3b584d34 100644 --- a/checks/check_extra732 +++ b/checks/check_extra732 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra732="7.32" -CHECK_TITLE_extra732="[extra732] Check if Geo restrictions are enabled in CloudFront distributions (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra732="[extra732] Check if Geo restrictions are enabled in CloudFront distributions" CHECK_SCORED_extra732="NOT_SCORED" CHECK_TYPE_extra732="EXTRA" CHECK_SEVERITY_extra732="Low" @@ -30,12 +30,12 @@ extra732(){ 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 "CloudFront distribution $dist has not Geo restrictions" + textFail "$REGION: CloudFront distribution $dist has not Geo restrictions" "$REGION" "$dist" else - textPass "CloudFront distribution $dist has Geo restrictions enabled" + textPass "$REGION: CloudFront distribution $dist has Geo restrictions enabled" "$REGION" "$dist" fi done else - textInfo "No CloudFront distributions found" + textInfo "$REGION: No CloudFront distributions found" fi } diff --git a/checks/check_extra733 b/checks/check_extra733 index 3fa7e785..24ea3275 100644 --- a/checks/check_extra733 +++ b/checks/check_extra733 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra733="7.33" -CHECK_TITLE_extra733="[extra733] Check if there are SAML Providers then STS can be used (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra733="[extra733] Check if there are SAML Providers then STS can be used" CHECK_SCORED_extra733="NOT_SCORED" CHECK_TYPE_extra733="EXTRA" CHECK_SEVERITY_extra733="Low" @@ -29,9 +29,9 @@ extra733(){ if [[ $LIST_SAML_PROV ]]; then for provider in $LIST_SAML_PROV; do PROVIDER_NAME=$(echo $provider| cut -d/ -f2) - textInfo "SAML Provider $PROVIDER_NAME has been found" + textInfo "$REGION: SAML Provider $PROVIDER_NAME has been found" "$REGION" "$PROVIDER_NAME" done else - textInfo "No SAML Provider found. Add one and use STS" + textFail "$REGION: No SAML Provider found. Add one and use STS" "$REGION" "$PROVIDER_NAME" fi } diff --git a/checks/check_extra734 b/checks/check_extra734 index 3d66582e..bb6e2ae5 100644 --- a/checks/check_extra734 +++ b/checks/check_extra734 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra734="7.34" -CHECK_TITLE_extra734="[extra734] Check if S3 buckets have default encryption (SSE) enabled or use a bucket policy to enforce it (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra734="[extra734] Check if S3 buckets have default encryption (SSE) enabled or use a bucket policy to enforce it" CHECK_SCORED_extra734="NOT_SCORED" CHECK_TYPE_extra734="EXTRA" CHECK_SEVERITY_extra734="Medium" @@ -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 "Access Denied Trying to Get Bucket Location for $bucket" + textFail "$BUCKET_LOCATION Access Denied Trying to Get Bucket Location for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi if [[ $BUCKET_LOCATION == "None" ]]; then @@ -46,13 +46,13 @@ 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 "Access Denied Trying to Get Encryption for $bucket" + textFail "$BUCKET_LOCATION: Access Denied Trying to Get Encryption for $bucket" "$BUCKET_LOCATION" "$bucket" continue fi if [[ $RESULT == "AES256" || $RESULT == "aws:kms" ]]; then - textPass "Bucket $bucket is enabled for default encryption with $RESULT" + textPass "$BUCKET_LOCATION: Bucket $bucket is enabled for default encryption with $RESULT" "$BUCKET_LOCATION" "$bucket" continue fi @@ -61,12 +61,12 @@ 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 "Access Denied Trying to Get Bucket Policy for $bucket" + textFail "$BUCKET_LOCATION: Access Denied Trying to Get Bucket Policy for $bucket" "$BUCKET_LOCATION" "$bucket" rm -f $TEMP_SSE_POLICY_FILE continue fi if [[ $(grep NoSuchBucketPolicy $TEMP_SSE_POLICY_FILE) ]]; then - textFail "No bucket policy for $bucket" + textFail "$BUCKET_LOCATION: No bucket policy for $bucket" "$BUCKET_LOCATION" "$bucket" rm -f $TEMP_SSE_POLICY_FILE continue fi @@ -74,18 +74,18 @@ extra734(){ # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | jq --arg arn "arn:${AWS_PARTITION}:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and ((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*") and .Action=="s3:PutObject" and .Resource==$arn and .Condition.StringEquals."s3:x-amz-server-side-encryption" != null)') if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT == "" ]]; then - textFail "Bucket $bucket does not enforce encryption!" + textFail "$BUCKET_LOCATION: Bucket $bucket does not enforce encryption!" "$BUCKET_LOCATION" "$bucket" rm -f $TEMP_SSE_POLICY_FILE continue fi CHECK_BUCKET_SSE_POLICY_VALUE=$(echo "$CHECK_BUCKET_SSE_POLICY_PRESENT" | jq -r '.Condition.StringNotEquals."s3:x-amz-server-side-encryption"') - textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" + textPass "$BUCKET_LOCATION: Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" "$BUCKET_LOCATION" "$bucket" rm -f $TEMP_SSE_POLICY_FILE done else - textInfo "No S3 Buckets found" + textInfo "$REGION No S3 Buckets found" "$REGION" fi } diff --git a/checks/check_extra735 b/checks/check_extra735 index 0b789f5e..72cb30f9 100644 --- a/checks/check_extra735 +++ b/checks/check_extra735 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra735="7.35" -CHECK_TITLE_extra735="[extra735] Check if RDS instances storage is encrypted (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra735="[extra735] Check if RDS instances storage is encrypted" CHECK_SCORED_extra735="NOT_SCORED" CHECK_TYPE_extra735="EXTRA" CHECK_SEVERITY_extra735="Medium" @@ -25,20 +25,19 @@ CHECK_DOC_extra735='https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overv CHECK_CAF_EPIC_extra735='Data Protection' extra735(){ - textInfo "Looking for RDS Volumes in all regions... " for regx in $REGIONS; do LIST_OF_RDS_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[*].DBInstanceIdentifier' --output text) 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) if [[ $IS_ENCRYPTED == "False" ]]; then - textFail "$regx: RDS instance $rdsinstance is not encrypted!" "$regx" + textFail "$regx: RDS instance $rdsinstance is not encrypted!" "$regx" "$rdsinstance" else - textPass "$regx: RDS instance $rdsinstance is encrypted" "$regx" + textPass "$regx: RDS instance $rdsinstance is encrypted" "$regx" "$rdsinstance" fi done else - textInfo "$regx: No RDS instances found" "$regx" + textInfo "$regx: No RDS instances found" "$regx" "$rdsinstance" fi done } diff --git a/checks/check_extra736 b/checks/check_extra736 index f9266d65..1c87be8e 100644 --- a/checks/check_extra736 +++ b/checks/check_extra736 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra736="7.36" -CHECK_TITLE_extra736="[extra736] Check exposed KMS keys (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra736="[extra736] Check exposed KMS keys" CHECK_SCORED_extra736="NOT_SCORED" CHECK_TYPE_extra736="EXTRA" CHECK_SEVERITY_extra736="Critical" @@ -25,16 +25,15 @@ CHECK_DOC_extra736='https://docs.aws.amazon.com/kms/latest/developerguide/determ CHECK_CAF_EPIC_extra736='Data Protection' extra736(){ - textInfo "Looking for KMS keys in all regions... " for regx in $REGIONS; do - LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --output text |grep -v :alias/aws/ |awk '{ print $4 }') + LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --query "Aliases[].[AliasName,TargetKeyId]" --output text |grep -v ^alias/aws/ |awk '{ print $2 }') if [[ $LIST_OF_CUSTOMER_KMS_KEYS ]];then for key in $LIST_OF_CUSTOMER_KMS_KEYS; do CHECK_POLICY=$($AWSCLI kms get-key-policy --key-id $key --policy-name default $PROFILE_OPT --region $regx --output text|awk '/Principal/{n=NR+1} n>=NR' |grep AWS\"\ :\ \"\\*\"$) if [[ $CHECK_POLICY ]]; then - textFail "$regx: KMS key $key may be publicly accessible!" "$regx" + textFail "$regx: KMS key $key may be publicly accessible!" "$regx" "$key" else - textPass "$regx: KMS key $key is not exposed to Public" "$regx" + textPass "$regx: KMS key $key is not exposed to Public" "$regx" "$key" fi done else diff --git a/checks/check_extra737 b/checks/check_extra737 deleted file mode 100644 index dc159378..00000000 --- a/checks/check_extra737 +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -CHECK_ID_extra737="7.37" -CHECK_TITLE_extra737="[extra737] Check KMS keys with key rotation disabled (Not Scored) (Not part of CIS benchmark)" -CHECK_SCORED_extra737="NOT_SCORED" -CHECK_TYPE_extra737="EXTRA" -CHECK_SEVERITY_extra737="Medium" -CHECK_ASFF_RESOURCE_TYPE_extra737="AwsKmsKey" -CHECK_ALTERNATE_check737="extra737" -CHECK_ASFF_COMPLIANCE_TYPE_extra737="ens-op.exp.11.aws.kms.3" -CHECK_SERVICENAME_extra737="kms" -CHECK_RISK_extra737='Cryptographic best practices discourage extensive reuse of encryption keys. Consequently; Customer Master Keys (CMKs) should be rotated to prevent usage of compromised keys.' -CHECK_REMEDIATION_extra737='For every KMS Customer Master Keys (CMKs); ensure that Rotate this key every year is enabled.' -CHECK_DOC_extra737='https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html' -CHECK_CAF_EPIC_extra737='Data Protection' - -extra737(){ - textInfo "Looking for KMS keys in all regions... " - for regx in $REGIONS; do - LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --output text |grep -v :alias/aws/ |awk '{ print $4 }') - if [[ $LIST_OF_CUSTOMER_KMS_KEYS ]];then - for key in $LIST_OF_CUSTOMER_KMS_KEYS; do - CHECK_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text) - CHECK_STATUS=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --output json | jq -r '.KeyMetadata.KeyState') - if [[ $CHECK_STATUS == "PendingDeletion" ]]; then - textInfo "$regx: KMS key $key is pending deletion and cannot be rotated" "$regx" - elif [[ $CHECK_ROTATION == "False" ]]; then - textFail "$regx: KMS key $key has rotation disabled!" "$regx" - else - textPass "$regx: KMS key $key has rotation enabled" "$regx" - fi - done - else - textInfo "$regx: No KMS keys found" "$regx" - fi - done -} diff --git a/checks/check_extra738 b/checks/check_extra738 index 1ea1c457..2a637a9d 100644 --- a/checks/check_extra738 +++ b/checks/check_extra738 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra738="7.38" -CHECK_TITLE_extra738="[extra738] Check if CloudFront distributions are set to HTTPS (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra738="[extra738] Check if CloudFront distributions are set to HTTPS" CHECK_SCORED_extra738="NOT_SCORED" CHECK_TYPE_extra738="EXTRA" CHECK_SEVERITY_extra738="Medium" @@ -30,14 +30,14 @@ extra738(){ for dist in $LIST_OF_DISTRIBUTIONS; do CHECK_HTTPS_STATUS=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.DefaultCacheBehavior.ViewerProtocolPolicy $PROFILE_OPT --output text) if [[ $CHECK_HTTPS_STATUS == "allow-all" ]]; then - textFail "CloudFront distribution $dist viewers can use HTTP or HTTPS!" "$regx" + textFail "$REGION: CloudFront distribution $dist viewers can use HTTP or HTTPS!" "$REGION" "$dist" elif [[ $CHECK_HTTPS_STATUS == "redirect-to-https" ]]; then - textPass "CloudFront distribution $dist has redirect to HTTPS" "$regx" + textPass "$REGION: CloudFront distribution $dist has redirect to HTTPS" "$REGION" "$dist" else - textPass "CloudFront distribution $dist has HTTPS only" "$regx" + textPass "$REGION: CloudFront distribution $dist has HTTPS only" "$REGION" "$dist" fi done else - textInfo "No CloudFront distributions found" "$regx" + textInfo "$REGION: No CloudFront distributions found" "$REGION" fi } diff --git a/checks/check_extra739 b/checks/check_extra739 index e36f4ab1..0dea5d78 100644 --- a/checks/check_extra739 +++ b/checks/check_extra739 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra739="7.39" -CHECK_TITLE_extra739="[extra739] Check if RDS instances have backup enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra739="[extra739] Check if RDS instances have backup enabled" CHECK_SCORED_extra739="NOT_SCORED" CHECK_TYPE_extra739="EXTRA" CHECK_SEVERITY_extra739="Medium" @@ -31,13 +31,13 @@ extra739(){ # if retention is 0 then is disabled BACKUP_RETENTION=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].BackupRetentionPeriod' --output text) if [[ $BACKUP_RETENTION == "0" ]]; then - textFail "$regx: RDS instance $rdsinstance has not backup enabled!" "$regx" + textFail "$regx: RDS instance $rdsinstance has not backup enabled!" "$regx" "$rdsinstance" else - textPass "$regx: RDS instance $rdsinstance has backup enabled with retention period $BACKUP_RETENTION days" "$regx" + textPass "$regx: RDS instance $rdsinstance has backup enabled with retention period $BACKUP_RETENTION days" "$regx" "$rdsinstance" fi done else - textInfo "$regx: No RDS instances found" "$regx" + textInfo "$regx: No RDS instances found" "$regx" "$rdsinstance" fi done } diff --git a/checks/check_extra74 b/checks/check_extra74 index 6ffa01d8..7d94a6a9 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra74="7.4" -CHECK_TITLE_extra74="[extra74] Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra74="[extra74] Ensure there are no Security Groups without ingress filtering being used" CHECK_SCORED_extra74="NOT_SCORED" CHECK_TYPE_extra74="EXTRA" CHECK_SEVERITY_extra74="High" @@ -27,16 +27,15 @@ CHECK_DOC_extra74='https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Security CHECK_CAF_EPIC_extra74='Infrastructure Security' extra74(){ - # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for Security Groups in all regions... " + # "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) for SG_ID in $LIST_OF_SECURITYGROUPS; do SG_NO_INGRESS_FILTER=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then - textFail "$regx: $SG_ID has no ingress filtering and it is being used!" "$regx" + textFail "$regx: $SG_ID has no ingress filtering and it is being used!" "$regx" "$SG_ID" else - textInfo "$regx: $SG_ID has no ingress filtering but it is not being used" "$regx" + textInfo "$regx: $SG_ID has no ingress filtering but it is not being used" "$regx" "$SG_ID" fi done done diff --git a/checks/check_extra740 b/checks/check_extra740 index 37f81434..7f771663 100644 --- a/checks/check_extra740 +++ b/checks/check_extra740 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra740="7.40" -CHECK_TITLE_extra740="[extra740] Check if EBS snapshots are encrypted (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra740="[extra740] Check if EBS snapshots are encrypted" CHECK_SCORED_extra740="NOT_SCORED" CHECK_TYPE_extra740="EXTRA" CHECK_SEVERITY_extra740="Medium" @@ -25,7 +25,6 @@ CHECK_DOC_extra740='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncry CHECK_CAF_EPIC_extra740='Data Protection' extra740(){ - textInfo "Examining EBS Volume Snapshots ..." # This does NOT use max-items, which would limit the number of items # considered. It considers all snapshots, but only reports at most # max-items passing and max-items failing. @@ -47,7 +46,7 @@ extra740(){ for snapshot in ${UNENCRYPTED_SNAPSHOTS}; do unencrypted=${unencrypted}+1 if [ "${unencrypted}" -le "${MAXITEMS}" ]; then - textFail "${regx}: ${snapshot} is not encrypted!" "${regx}" + textFail "${regx}: ${snapshot} is not encrypted!" "${regx}" "${snapshot}" fi done fi @@ -55,7 +54,7 @@ extra740(){ for snapshot in ${ENCRYPTED_SNAPSHOTS}; do encrypted=${encrypted}+1 if [ "${encrypted}" -le "${MAXITEMS}" ]; then - textPass "${regx}: ${snapshot} is encrypted." "${regx}" + textPass "${regx}: ${snapshot} is encrypted." "${regx}" "${snapshot}" fi done fi diff --git a/checks/check_extra741 b/checks/check_extra741 index 023e4f00..ebf12543 100644 --- a/checks/check_extra741 +++ b/checks/check_extra741 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra741="7.41" -CHECK_TITLE_extra741="[extra741] Find secrets in EC2 User Data (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra741="[extra741] Find secrets in EC2 User Data" CHECK_SCORED_extra741="NOT_SCORED" CHECK_TYPE_extra741="EXTRA" CHECK_SEVERITY_extra741="Critical" @@ -30,7 +30,6 @@ extra741(){ mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in EC2 User Data in instances across all regions... (max 100 instances per region use -m to increase it) " 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) if [[ $LIST_OF_EC2_INSTANCES ]];then @@ -47,16 +46,16 @@ extra741(){ fi FINDINGS=$(secretsDetector file "$EC2_USERDATA_FILE") if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in $instance User Data" "$regx" + textPass "$regx: No secrets found in $instance User Data" "$regx" "$instance" # delete file if nothing interesting is there rm -f "$EC2_USERDATA_FILE" else - textFail "$regx: Potential secret found in $instance User Data" "$regx" + textFail "$regx: Potential secret found in $instance User Data" "$regx" "$regx" "$instance" # delete file to not leave trace, user must look at the instance User Data rm -f "$EC2_USERDATA_FILE" fi else - textPass "$regx: No secrets found in $instance User Data or it is empty" "$regx" + textPass "$regx: No secrets found in $instance User Data or it is empty" "$regx" "$instance" fi done else diff --git a/checks/check_extra742 b/checks/check_extra742 index d6083ef0..6c78c7a9 100644 --- a/checks/check_extra742 +++ b/checks/check_extra742 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra742="7.42" -CHECK_TITLE_extra742="[extra742] Find secrets in CloudFormation outputs (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra742="[extra742] Find secrets in CloudFormation outputs" CHECK_SCORED_extra742="NOT_SCORED" CHECK_TYPE_extra742="EXTRA" CHECK_SEVERITY_extra742="Critical" @@ -30,7 +30,6 @@ extra742(){ mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in CloudFormation output across all regions... " for regx in $REGIONS; do CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --output json) LIST_OF_CFN_STACKS=$(echo $CFN_STACKS | jq -r '.Stacks[].StackName') @@ -45,11 +44,11 @@ extra742(){ # New implementation using https://github.com/Yelp/detect-secrets FINDINGS=$(secretsDetector file $CFN_OUTPUTS_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in stack $stack Outputs" "$regx" + textPass "$regx: No secrets found in stack $stack Outputs" "$regx" "$stack" # delete file if nothing interesting is there rm -f $CFN_OUTPUTS_FILE else - textFail "$regx: Potential secret found in stack $stack Outputs" "$regx" + textFail "$regx: Potential secret found in stack $stack Outputs" "$regx" "$stack" # delete file to not leave trace, user must look at the CFN Stack rm -f $CFN_OUTPUTS_FILE fi diff --git a/checks/check_extra743 b/checks/check_extra743 index e7e21965..b5c365a4 100644 --- a/checks/check_extra743 +++ b/checks/check_extra743 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra743="7.43" -CHECK_TITLE_extra743="[extra743] Check if API Gateway has client certificate enabled to access your backend endpoint (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra743="[extra743] Check if API Gateway has client certificate enabled to access your backend endpoint" CHECK_SCORED_extra743="NOT_SCORED" CHECK_TYPE_extra743="EXTRA" CHECK_SEVERITY_extra743="Medium" @@ -34,9 +34,9 @@ extra743(){ for stage in $LIST_OF_STAGES; do CHECK_CERTIFICATE=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-stages --rest-api-id $api --query "item[?stageName==\`$stage\`].clientCertificateId" --output text) if [[ $CHECK_CERTIFICATE ]]; then - textPass "$regx: API Gateway $API_GW_NAME ID $api in $stage has client certificate enabled" "$regx" + textPass "$regx: API Gateway $API_GW_NAME ID $api in $stage has client certificate enabled" "$regx" "$API_GW_NAME" else - textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not client certificate enabled" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not client certificate enabled" "$regx" "$API_GW_NAME" fi done fi diff --git a/checks/check_extra744 b/checks/check_extra744 index 36ed0705..48cf6f11 100644 --- a/checks/check_extra744 +++ b/checks/check_extra744 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra744="7.44" -CHECK_TITLE_extra744="[extra744] Check if API Gateway has a WAF ACL attached (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra744="[extra744] Check if API Gateway has a WAF ACL attached" CHECK_SCORED_extra744="NOT_SCORED" CHECK_TYPE_extra744="EXTRA" CHECK_SEVERITY_extra744="Medium" @@ -35,9 +35,9 @@ extra744(){ for stage in $LIST_OF_STAGES; do CHECK_WAFACL=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-stages --rest-api-id $api --query "item[?stageName==\`$stage\`].webAclArn" --output text) if [[ $CHECK_WAFACL ]]; then - textPass "$regx: API Gateway $API_GW_NAME ID $api in $stage has $CHECK_WAFACL WAF ACL attached" "$regx" + textPass "$regx: API Gateway $API_GW_NAME ID $api in $stage has $CHECK_WAFACL WAF ACL attached" "$regx" "$API_GW_NAME" else - textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not WAF ACL attached" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not WAF ACL attached" "$regx" "$API_GW_NAME" fi done fi diff --git a/checks/check_extra745 b/checks/check_extra745 index 0b507d7b..1ee49e72 100644 --- a/checks/check_extra745 +++ b/checks/check_extra745 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra745="7.45" -CHECK_TITLE_extra745="[extra745] Check if API Gateway endpoint is public or private (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra745="[extra745] Check if API Gateway endpoint is public or private" CHECK_SCORED_extra745="NOT_SCORED" CHECK_TYPE_extra745="EXTRA" CHECK_SEVERITY_extra745="Medium" @@ -33,13 +33,13 @@ extra745(){ if [[ $ENDPOINT_CONFIG_TYPE ]]; then case $ENDPOINT_CONFIG_TYPE in PRIVATE ) - textPass "$regx: API Gateway $API_GW_NAME ID $api is set as $ENDPOINT_CONFIG_TYPE" "$regx" + textPass "$regx: API Gateway $API_GW_NAME ID $api is set as $ENDPOINT_CONFIG_TYPE" "$regx" "$API_GW_NAME" ;; REGIONAL ) - textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx" "$API_GW_NAME" ;; EDGE ) - textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx" "$API_GW_NAME" esac fi done diff --git a/checks/check_extra746 b/checks/check_extra746 index 82f82d53..638d15ef 100644 --- a/checks/check_extra746 +++ b/checks/check_extra746 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra746="7.46" -CHECK_TITLE_extra746="[extra746] Check if API Gateway has configured authorizers (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra746="[extra746] Check if API Gateway has configured authorizers" CHECK_SCORED_extra746="NOT_SCORED" CHECK_TYPE_extra746="EXTRA" CHECK_SEVERITY_extra746="Medium" @@ -31,9 +31,9 @@ extra746(){ API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text) AUTHORIZER_CONFIGURED=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-authorizers --rest-api-id $api --query items[*].type --output text) if [[ $AUTHORIZER_CONFIGURED ]]; then - textPass "$regx: API Gateway $API_GW_NAME ID $api has authorizer configured" "$regx" + textPass "$regx: API Gateway $API_GW_NAME ID $api has authorizer configured" "$regx" "$API_GW_NAME" else - textFail "$regx: API Gateway $API_GW_NAME ID $api has not authorizer configured" "$regx" + textFail "$regx: API Gateway $API_GW_NAME ID $api has not authorizer configured" "$regx" "$API_GW_NAME" fi done else diff --git a/checks/check_extra747 b/checks/check_extra747 index f2473563..2b2ede3b 100644 --- a/checks/check_extra747 +++ b/checks/check_extra747 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra747="7.47" -CHECK_TITLE_extra747="[extra747] Check if RDS instances is integrated with CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra747="[extra747] Check if RDS instances is integrated with CloudWatch Logs" CHECK_SCORED_extra747="NOT_SCORED" CHECK_TYPE_extra747="EXTRA" CHECK_SEVERITY_extra747="Medium" @@ -31,13 +31,13 @@ extra747(){ # if retention is 0 then is disabled ENABLED_CLOUDWATCHLOGS_EXPORTS=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --db-instance-identifier $rdsinstance --query 'DBInstances[*].EnabledCloudwatchLogsExports' --output text) if [[ $ENABLED_CLOUDWATCHLOGS_EXPORTS ]]; then - textPass "$regx: RDS instance $rdsinstance is shipping $ENABLED_CLOUDWATCHLOGS_EXPORTS to CloudWatch Logs" "$regx" + textPass "$regx: RDS instance $rdsinstance is shipping $ENABLED_CLOUDWATCHLOGS_EXPORTS to CloudWatch Logs" "$regx" "$rdsinstance" else - textFail "$regx: RDS instance $rdsinstance has no CloudWatch Logs enabled!" "$regx" + textFail "$regx: RDS instance $rdsinstance has no CloudWatch Logs enabled!" "$regx" "$rdsinstance" fi done else - textInfo "$regx: No RDS instances found" "$regx" + textInfo "$regx: No RDS instances found" "$regx" "$rdsinstance" fi done } diff --git a/checks/check_extra748 b/checks/check_extra748 index 245b40b4..f46ef6c5 100644 --- a/checks/check_extra748 +++ b/checks/check_extra748 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra748="7.48" -CHECK_TITLE_extra748="[extra748] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to any port (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra748="[extra748] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to any port" CHECK_SCORED_extra748="NOT_SCORED" CHECK_TYPE_extra748="EXTRA" CHECK_SEVERITY_extra748="High" @@ -28,7 +28,7 @@ extra748(){ 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) if [[ $SG_LIST ]];then for SG in $SG_LIST;do - textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0" "$regx" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0" "$regx" "$SG" done else textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0" "$regx" diff --git a/checks/check_extra749 b/checks/check_extra749 index 4acf5f35..820d2f68 100644 --- a/checks/check_extra749 +++ b/checks/check_extra749 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra749="7.49" -CHECK_TITLE_extra749="[extra749] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Oracle ports 1521 or 2483 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra749="[extra749] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Oracle ports 1521 or 2483" CHECK_SCORED_extra749="NOT_SCORED" CHECK_TYPE_extra749="EXTRA" CHECK_SEVERITY_extra749="High" @@ -29,7 +29,7 @@ extra749(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Oracle ports" "$regx" "$SG" done else textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Oracle ports" "$regx" diff --git a/checks/check_extra75 b/checks/check_extra75 index f6e97ccb..34a05fb8 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra75="7.5" -CHECK_TITLE_extra75="[extra75] Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra75="[extra75] Ensure there are no Security Groups not being used" CHECK_SCORED_extra75="NOT_SCORED" CHECK_TYPE_extra75="EXTRA" CHECK_SEVERITY_extra75="Informational" @@ -27,9 +27,7 @@ CHECK_DOC_extra75='https://aws.amazon.com/premiumsupport/knowledge-center/ec2-fi CHECK_CAF_EPIC_extra75='Infrastructure Security' extra75(){ - # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for Security Groups in all regions... " - + # "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" ]]; @@ -44,12 +42,12 @@ extra75(){ GROUP_NAME=$(echo $SECURITYGROUPS | jq -r --arg id $SG_ID '.[$id]') if [[ $GROUP_NAME != "default" ]]; then - textFail "$regx: $SG_ID is not being used!" "$regx" + textFail "$regx: $SG_ID is not being used!" "$regx" "$SG_ID" else - textInfo "$regx: $SG_ID is not being used - default security group" "$regx" + textInfo "$regx: $SG_ID is not being used - default security group" "$regx" "$SG_ID" fi else - textPass "$regx: $SG_ID is being used" "$regx" + textPass "$regx: $SG_ID is being used" "$regx" "$SG_ID" fi done done diff --git a/checks/check_extra750 b/checks/check_extra750 index 54b09ac1..62dcf115 100644 --- a/checks/check_extra750 +++ b/checks/check_extra750 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra750="7.50" -CHECK_TITLE_extra750="[extra750] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MySQL port 3306 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra750="[extra750] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MySQL port 3306" CHECK_SCORED_extra750="NOT_SCORED" CHECK_TYPE_extra750="EXTRA" CHECK_SEVERITY_extra750="High" @@ -29,7 +29,7 @@ extra750(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for MySQL port" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for MySQL port" "$regx" diff --git a/checks/check_extra751 b/checks/check_extra751 index 5e44d87b..c98cd4fe 100644 --- a/checks/check_extra751 +++ b/checks/check_extra751 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra751="7.51" -CHECK_TITLE_extra751="[extra751] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra751="[extra751] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432" CHECK_SCORED_extra751="NOT_SCORED" CHECK_TYPE_extra751="EXTRA" CHECK_SEVERITY_extra751="High" @@ -29,7 +29,7 @@ extra751(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Postgres port" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Postgres port" "$regx" diff --git a/checks/check_extra752 b/checks/check_extra752 index 815f3f01..07aa549d 100644 --- a/checks/check_extra752 +++ b/checks/check_extra752 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra752="7.52" -CHECK_TITLE_extra752="[extra752] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Redis port 6379 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra752="[extra752] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Redis port 6379" CHECK_SCORED_extra752="NOT_SCORED" CHECK_TYPE_extra752="EXTRA" CHECK_SEVERITY_extra752="High" @@ -29,7 +29,7 @@ extra752(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Redis port" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Redis port" "$regx" diff --git a/checks/check_extra753 b/checks/check_extra753 index 150a8c14..34042b6e 100644 --- a/checks/check_extra753 +++ b/checks/check_extra753 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra753="7.53" -CHECK_TITLE_extra753="[extra753] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra753="[extra753] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018" CHECK_SCORED_extra753="NOT_SCORED" CHECK_TYPE_extra753="EXTRA" CHECK_SEVERITY_extra753="High" @@ -29,7 +29,7 @@ extra753(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for MongoDB ports" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for MongoDB ports" "$regx" diff --git a/checks/check_extra754 b/checks/check_extra754 index 8046782f..4277fe4f 100644 --- a/checks/check_extra754 +++ b/checks/check_extra754 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra754="7.54" -CHECK_TITLE_extra754="[extra754] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra754="[extra754] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888" CHECK_SCORED_extra754="NOT_SCORED" CHECK_TYPE_extra754="EXTRA" CHECK_SEVERITY_extra754="High" @@ -29,7 +29,7 @@ extra754(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Cassandra ports" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Cassandra ports" "$regx" diff --git a/checks/check_extra755 b/checks/check_extra755 index 45460007..50430f1a 100644 --- a/checks/check_extra755 +++ b/checks/check_extra755 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra755="7.55" -CHECK_TITLE_extra755="[extra755] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra755="[extra755] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211" CHECK_SCORED_extra755="NOT_SCORED" CHECK_TYPE_extra755="EXTRA" CHECK_SEVERITY_extra755="High" @@ -29,7 +29,7 @@ extra755(){ 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) 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" + textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0 for Memcached port" "$regx" "$SG" done else textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Memcached port" "$regx" diff --git a/checks/check_extra756 b/checks/check_extra756 deleted file mode 100644 index 5e33bcc5..00000000 --- a/checks/check_extra756 +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -CHECK_ID_extra756="7.56" -CHECK_TITLE_extra756="[extra756] Check if Redshift cluster is Public Accessible (Not Scored) (Not part of CIS benchmark)" -CHECK_SCORED_extra756="NOT_SCORED" -CHECK_TYPE_extra756="EXTRA" -CHECK_SEVERITY_extra756="High" -CHECK_ASFF_RESOURCE_TYPE_extra756="AwsRedshiftCluster" -CHECK_ALTERNATE_check756="extra756" -CHECK_SERVICENAME_extra756="redshift" -CHECK_RISK_extra756='Publicly accessible services could expose sensible data to bad actors.' -CHECK_REMEDIATION_extra756='Ensure there is a business requirement for service to be public. Use the cluster security group to control access to the service.' -CHECK_DOC_extra756='https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-security-groups.html' -CHECK_CAF_EPIC_extra756='Infrastructure Security' - -extra756(){ - for regx in $REGIONS; do - LIST_OF_RS_CLUSTERS=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --query Clusters[*].ClusterIdentifier --output text) - if [[ $LIST_OF_RS_CLUSTERS ]];then - for cluster in $LIST_OF_RS_CLUSTERS; do - IS_PUBLICLY_ACCESSIBLE=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --cluster-identifier $cluster --query Clusters[*].PubliclyAccessible --output text|grep True) - if [[ $IS_PUBLICLY_ACCESSIBLE ]]; then - textFail "$regx: Redshift cluster $cluster is publicly accessible" "$regx" - else - textPass "$regx: Redshift cluster $cluster is not publicly accessible" "$regx" - fi - done - else - textInfo "$regx: No Redshift clusters found" "$regx" - fi - done -} diff --git a/checks/check_extra757 b/checks/check_extra757 index 23c8bff8..364caab7 100644 --- a/checks/check_extra757 +++ b/checks/check_extra757 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra757="7.57" -CHECK_TITLE_extra757="[extra757] Check EC2 Instances older than 6 months (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra757="[extra757] Check EC2 Instances older than 6 months" CHECK_SCORED_extra757="NOT_SCORED" CHECK_TYPE_extra757="EXTRA" CHECK_SEVERITY_extra757="Medium" @@ -25,7 +25,6 @@ CHECK_CAF_EPIC_extra757='Infrastructure Security' extra757(){ OLDAGE="$(get_date_previous_than_months 6)" - textInfo "Looking for EC2 instances in all regions..." for regx in $REGIONS; do EC2_RUNNING="$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text)" if [[ $EC2_RUNNING ]]; then @@ -35,7 +34,7 @@ extra757(){ do EC2_ID=$(echo "$ec2_instace" | awk '{print $1}') LAUNCH_DATE=$(echo "$ec2_instace" | awk '{print $2}') - textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx" + textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx" "$EC2_ID" done <<< "$INSTACES_OLD_THAN_AGE" else textPass "$regx: All Instances newer than 6 months" "$regx" diff --git a/checks/check_extra758 b/checks/check_extra758 index b4c483cd..0beabcf4 100644 --- a/checks/check_extra758 +++ b/checks/check_extra758 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra758="7.58" -CHECK_TITLE_extra758="[extra758] Check EC2 Instances older than 12 months (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra758="[extra758] Check EC2 Instances older than 12 months " CHECK_SCORED_extra758="NOT_SCORED" CHECK_TYPE_extra758="EXTRA" CHECK_SEVERITY_extra758="Medium" @@ -25,7 +25,6 @@ CHECK_CAF_EPIC_extra758='Infrastructure Security' extra758(){ OLDAGE="$(get_date_previous_than_months 12)" - textInfo "Looking for EC2 instances in all regions..." for regx in $REGIONS; do EC2_RUNNING="$($AWSCLI ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" $PROFILE_OPT --region $regx --output text)" if [[ $EC2_RUNNING ]]; then @@ -35,7 +34,7 @@ extra758(){ do EC2_ID=$(echo "$ec2_instace" | awk '{print $1}') LAUNCH_DATE=$(echo "$ec2_instace" | awk '{print $2}') - textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx" + textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx" "$EC2_ID" done <<< "$INSTACES_OLD_THAN_AGE" else textPass "$regx: All Instances newer than 12 months" "$regx" diff --git a/checks/check_extra759 b/checks/check_extra759 index 01c6bebb..15f73fcd 100644 --- a/checks/check_extra759 +++ b/checks/check_extra759 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra759="7.59" -CHECK_TITLE_extra759="[extra759] Find secrets in Lambda functions variables (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra759="[extra759] Find secrets in Lambda functions variables " CHECK_SCORED_extra759="NOT_SCORED" CHECK_TYPE_extra759="EXTRA" CHECK_SEVERITY_extra759="Critical" @@ -30,7 +30,6 @@ extra759(){ mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in Lambda variables across all regions... " for regx in $REGIONS; do LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) if [[ $LIST_OF_FUNCTIONS ]]; then @@ -41,11 +40,11 @@ extra759(){ # Implementation using https://github.com/Yelp/detect-secrets FINDINGS=$(secretsDetector file $LAMBDA_FUNCTION_VARIABLES_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in Lambda function $lambdafunction variables" "$regx" + textPass "$regx: No secrets found in Lambda function $lambdafunction variables" "$regx" "$lambdafunction" # delete file if nothing interesting is there rm -f $LAMBDA_FUNCTION_VARIABLES_FILE else - textFail "$regx: Potential secret found in Lambda function $lambdafunction variables" "$regx" + textFail "$regx: Potential secret found in Lambda function $lambdafunction variables" "$regx" "$lambdafunction" # delete file to not leave trace, user must look at the function rm -f $LAMBDA_FUNCTION_VARIABLES_FILE fi diff --git a/checks/check_extra76 b/checks/check_extra76 index 854d48e7..9124b8cb 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra76="7.6" -CHECK_TITLE_extra76="[extra76] Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra76="[extra76] Ensure there are no EC2 AMIs set as Public" CHECK_SCORED_extra76="NOT_SCORED" CHECK_TYPE_extra76="EXTRA" CHECK_SEVERITY_extra76="Critical" @@ -25,16 +25,15 @@ CHECK_DOC_extra76='https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/usingshar CHECK_CAF_EPIC_extra76='Infrastructure Security' extra76(){ - # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for AMIs in all regions... " + # "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) if [[ $LIST_OF_PUBLIC_AMIS ]];then for ami in $LIST_OF_PUBLIC_AMIS; do - textFail "$regx: $ami is currently Public!" "$regx" + textFail "$regx: $ami is currently Public!" "$regx" "$ami" done else - textPass "$regx: No Public AMIs found" "$regx" + textPass "$regx: No Public AMIs found" "$regx" "$ami" fi done } diff --git a/checks/check_extra760 b/checks/check_extra760 index b75303ae..ca70b83f 100644 --- a/checks/check_extra760 +++ b/checks/check_extra760 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra760="7.60" -CHECK_TITLE_extra760="[extra760] Find secrets in Lambda functions code (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra760="[extra760] Find secrets in Lambda functions code " CHECK_SCORED_extra760="NOT_SCORED" CHECK_TYPE_extra760="EXTRA" CHECK_SEVERITY_extra760="Critical" @@ -30,8 +30,6 @@ extra760(){ mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in Lambda functions code across all regions... " - textInfo "This check may take a while depending on your functions size! " for regx in $REGIONS; do LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) if [[ $LIST_OF_FUNCTIONS ]]; then @@ -45,11 +43,11 @@ extra760(){ unzip -qq $LAMBDA_FUNCTION_FOLDER/$LAMBDA_FUNCTION_FILE -d $LAMBDA_FUNCTION_FOLDER FINDINGS=$(secretsDetector folder $LAMBDA_FUNCTION_FOLDER) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in Lambda function $lambdafunction code" "$regx" + textPass "$regx: No secrets found in Lambda function $lambdafunction code" "$regx" "$lambdafunction" # delete files if nothing interesting is there rm -fr $LAMBDA_FUNCTION_FOLDER else - textFail "$regx: Potential secret found in Lambda function $lambdafunction code" "$regx" + textFail "$regx: Potential secret found in Lambda function $lambdafunction code" "$regx" "$lambdafunction" # delete files to not leave trace, user must look at the function rm -fr $LAMBDA_FUNCTION_FOLDER fi diff --git a/checks/check_extra761 b/checks/check_extra761 index a8504632..34ecb953 100644 --- a/checks/check_extra761 +++ b/checks/check_extra761 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra761="7.61" -CHECK_TITLE_extra761="[extra761] Check if EBS Default Encryption is activated (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra761="[extra761] Check if EBS Default Encryption is activated " CHECK_SCORED_extra761="NOT_SCORED" CHECK_TYPE_extra761="EXTRA" CHECK_SEVERITY_extra761="Medium" @@ -24,15 +24,14 @@ CHECK_DOC_extra761='https://aws.amazon.com/premiumsupport/knowledge-center/ebs-a CHECK_CAF_EPIC_extra761='Data Protection' extra761(){ - textInfo "Looking for EBS Default Encryption activation in all regions... " for regx in $REGIONS; do EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault' 2>&1) if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep "argument operation: Invalid choice") ]]; then - textFail "Newer aws cli needed for get-ebs-encryption-by-default" + textFail "$regx: Newer aws cli needed for get-ebs-encryption-by-default" "$regx" continue fi if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then - textFail "Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" + textFail "$regx: Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" "$regx" continue fi if [[ $EBS_DEFAULT_ENCRYPTION == "true" ]];then diff --git a/checks/check_extra762 b/checks/check_extra762 index fe55e875..2345f058 100644 --- a/checks/check_extra762 +++ b/checks/check_extra762 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra762="7.62" -CHECK_TITLE_extra762="[extra762] Find obsolete Lambda runtimes (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra762="[extra762] Find obsolete Lambda runtimes " CHECK_SCORED_extra762="NOT_SCORED" CHECK_TYPE_extra762="EXTRA" CHECK_SEVERITY_extra762="Medium" @@ -36,9 +36,9 @@ extra762(){ fname=$(echo "$lambdafunction" | cut -d'%' -f1) runtime=$(echo "$lambdafunction" | cut -d'%' -f2) if echo "$lambdafunction" | grep -Eq $OBSOLETE ; then - textFail "$regx: Obsolete runtime: ${runtime} used by: ${fname}" "$regx" + textFail "$regx: Obsolete runtime: ${runtime} used by: ${fname}" "$regx" "${fname}" else - textPass "$regx: Supported runtime: ${runtime} used by: ${fname}" "$regx" + textPass "$regx: Supported runtime: ${runtime} used by: ${fname}" "$regx" "${fname}" fi done else diff --git a/checks/check_extra763 b/checks/check_extra763 index 79d35f1e..d2d53e0d 100644 --- a/checks/check_extra763 +++ b/checks/check_extra763 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra763="7.63" -CHECK_TITLE_extra763="[extra763] Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra763="[extra763] Check if S3 buckets have object versioning enabled " CHECK_SCORED_extra763="NOT_SCORED" CHECK_TYPE_extra763="EXTRA" CHECK_SEVERITY_extra763="Medium" @@ -24,7 +24,7 @@ CHECK_DOC_extra763='https://docs.aws.amazon.com/AmazonS3/latest/dev-retired/Vers CHECK_CAF_EPIC_extra763='Data Protection' extra763(){ - # "Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if S3 buckets have object versioning enabled " LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do @@ -34,9 +34,9 @@ extra763(){ continue fi if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then - textPass "Bucket $bucket has versioning enabled" + textPass "Bucket $bucket has versioning enabled" "us-east-1" "$bucket" else - textFail "Bucket $bucket has versioning disabled!" + textFail "Bucket $bucket has versioning disabled!" "us-east-1" "$bucket" fi done else diff --git a/checks/check_extra764 b/checks/check_extra764 index 426c53ae..67a6158c 100644 --- a/checks/check_extra764 +++ b/checks/check_extra764 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra764="7.64" -CHECK_TITLE_extra764="[extra764] Check if S3 buckets have secure transport policy (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra764="[extra764] Check if S3 buckets have secure transport policy " CHECK_SCORED_extra764="NOT_SCORED" CHECK_TYPE_extra764="EXTRA" CHECK_SEVERITY_extra764="Medium" @@ -49,7 +49,7 @@ extra764(){ continue fi if [[ $(grep NoSuchBucketPolicy $TEMP_STP_POLICY_FILE) ]]; then - textFail "No bucket policy for $bucket" + textFail "No bucket policy for $bucket" "us-east-1" "$bucket" rm -f $TEMP_STP_POLICY_FILE continue fi @@ -61,9 +61,9 @@ extra764(){ CHECK_BUCKET_STP_POLICY_PRESENT=$(cat $TEMP_STP_POLICY_FILE | jq --arg arn "arn:${AWS_PARTITION}:s3:::${bucket}" \ '.Statement[]|select((((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and .Effect=="Deny" and (.Action=="s3:*" or .Action=="*") and (.Resource|type == "array") and (.Resource|map({(.):0})[]|has($arn)) and (.Resource|map({(.):0})[]|has($arn+"/*")) and .Condition.Bool."aws:SecureTransport" == "false")') if [[ $CHECK_BUCKET_STP_POLICY_PRESENT ]]; then - textPass "Bucket $bucket has S3 bucket policy to deny requests over insecure transport" + textPass "Bucket $bucket has S3 bucket policy to deny requests over insecure transport" "us-east-1" "$bucket" else - textFail "Bucket $bucket allows requests over insecure transport" + textFail "Bucket $bucket allows requests over insecure transport" "us-east-1" "$bucket" fi else textInfo "Unknown Error occurred: $policy_str" diff --git a/checks/check_extra765 b/checks/check_extra765 index 8c23408f..38cdc508 100644 --- a/checks/check_extra765 +++ b/checks/check_extra765 @@ -21,7 +21,7 @@ # --image-scanning-configuration scanOnPush=true CHECK_ID_extra765="7.65" -CHECK_TITLE_extra765="[extra765] Check if ECR image scan on push is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra765="[extra765] Check if ECR image scan on push is enabled " CHECK_SCORED_extra765="NOT_SCORED" CHECK_TYPE_extra765="EXTRA" CHECK_SEVERITY_extra765="Medium" @@ -44,16 +44,16 @@ extra765(){ SCAN_ENABLED=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[?repositoryName==\`$repo\`].[imageScanningConfiguration.scanOnPush]" --output text 2>&1) case "$SCAN_ENABLED" in "True") - textPass "$region: ECR repository $repo has scan on push enabled" "$region" + textPass "$region: ECR repository $repo has scan on push enabled" "$region" "$repo" ;; "False") - textFail "$region: ECR repository $repo has scan on push disabled!" "$region" + 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" + 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" + textInfo "$region: ECR repository $repo has unknown scanOnPush status \"$SCAN_ENABLED\"" "$region" "$repo" ;; esac done diff --git a/checks/check_extra767 b/checks/check_extra767 index a87b0c52..7bff69fd 100644 --- a/checks/check_extra767 +++ b/checks/check_extra767 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra767="7.67" -CHECK_TITLE_extra767="[extra767] Check if CloudFront distributions have Field Level Encryption enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra767="[extra767] Check if CloudFront distributions have Field Level Encryption enabled " CHECK_SCORED_extra767="NOT_SCORED" CHECK_TYPE_extra767="EXTRA" CHECK_SEVERITY_extra767="Low" @@ -29,9 +29,9 @@ extra767(){ for dist in $LIST_OF_DISTRIBUTIONS; do CHECK_FLE=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.DefaultCacheBehavior.FieldLevelEncryptionId $PROFILE_OPT --output text) if [[ $CHECK_FLE ]]; then - textPass "CloudFront distribution $dist has Field Level Encryption enabled" "$regx" + textPass "CloudFront distribution $dist has Field Level Encryption enabled" "$regx" "$dist" else - textFail "CloudFront distribution $dist has Field Level Encryption disabled!" "$regx" + textFail "CloudFront distribution $dist has Field Level Encryption disabled!" "$regx" "$dist" fi done else diff --git a/checks/check_extra768 b/checks/check_extra768 index f0c6b3d1..dc222b5d 100644 --- a/checks/check_extra768 +++ b/checks/check_extra768 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra768="7.68" -CHECK_TITLE_extra768="[extra768] Find secrets in ECS task definitions variables (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra768="[extra768] Find secrets in ECS task definitions variables " CHECK_SCORED_extra768="NOT_SCORED" CHECK_TYPE_extra768="EXTRA" CHECK_SEVERITY_extra768="Critical" @@ -29,7 +29,6 @@ extra768(){ # this folder is deleted once this check is finished mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in ECS task definitions' environment variables across all regions... " for regx in $REGIONS; do # Get a list of all families first: FAMILIES=$($AWSCLI ecs list-task-definition-families $PROFILE_OPT --region $regx --status ACTIVE | jq -r .families[]) @@ -46,14 +45,14 @@ extra768(){ # Implementation using https://github.com/Yelp/detect-secrets FINDINGS=$(secretsDetector file $TASK_DEFINITION_ENV_VARIABLES_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in ECS task definition $TASK_DEFINITION variables" "$regx" + textPass "$regx: No secrets found in ECS task definition $TASK_DEFINITION variables" "$regx" "$TASK_DEFINITION" # delete file if nothing interesting is there rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE else - textFail "$regx: Potential secret found in ECS task definition $TASK_DEFINITION variables" "$regx" + textFail "$regx: Potential secret found in ECS task definition $TASK_DEFINITION variables" "$regx" "$TASK_DEFINITION" fi else - textInfo "$regx: ECS task definition $TASK_DEFINITION has no variables" "$regx" + textInfo "$regx: ECS task definition $TASK_DEFINITION has no variables" "$regx" "$TASK_DEFINITION" rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE fi done diff --git a/checks/check_extra769 b/checks/check_extra769 index 3d45692b..00e34e00 100644 --- a/checks/check_extra769 +++ b/checks/check_extra769 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra769="7.69" -CHECK_TITLE_extra769="[extra769] Check if IAM Access Analyzer is enabled and its findings (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra769="[extra769] Check if IAM Access Analyzer is enabled and its findings " CHECK_SCORED_extra769="NOT_SCORED" CHECK_TYPE_extra769="EXTRA" CHECK_SEVERITY_extra769="High" @@ -38,9 +38,9 @@ extra769(){ for accessAnalyzerArn in $LIST_OF_ACCESS_ANALYZERS;do ANALYZER_ACTIVE_FINDINGS_COUNT=$($AWSCLI accessanalyzer list-findings $PROFILE_OPT --region $regx --analyzer-arn $accessAnalyzerArn --query 'findings[?status == `ACTIVE`].[id,status]' --output text | wc -l | tr -d ' ') if [[ $ANALYZER_ACTIVE_FINDINGS_COUNT -eq 0 ]];then - textPass "$regx: IAM Access Analyzer $accessAnalyzerArn has no active findings" "$regx" + textPass "$regx: IAM Access Analyzer $accessAnalyzerArn has no active findings" "$regx" "$accessAnalyzerArn" else - textInfo "$regx: IAM Access Analyzer $accessAnalyzerArn has $ANALYZER_ACTIVE_FINDINGS_COUNT active findings" "$regx" + textInfo "$regx: IAM Access Analyzer $accessAnalyzerArn has $ANALYZER_ACTIVE_FINDINGS_COUNT active findings" "$regx" fi done else diff --git a/checks/check_extra77 b/checks/check_extra77 index 4391c320..d3cc4a50 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra77="7.7" -CHECK_TITLE_extra77="[extra77] Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra77="[extra77] Ensure there are no ECR repositories set as Public" CHECK_SCORED_extra77="NOT_SCORED" CHECK_TYPE_extra77="EXTRA" CHECK_SEVERITY_extra77="Critical" @@ -26,43 +26,43 @@ CHECK_DOC_extra77='https://docs.aws.amazon.com/AmazonECR/latest/public/security_ CHECK_CAF_EPIC_extra77='Data Protection' extra77(){ - # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" - for region in $REGIONS; do - LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[*].[repositoryName]" --output text 2>&1) + # "Ensure there are no ECR repositories set as Public " + 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 "Access Denied Trying to describe ECR repositories" + textFail "$regx: Access Denied Trying to describe ECR repositories" "$regx" "$repo" continue fi if [[ $(echo "$LIST_ECR_REPOS" | grep SubscriptionRequiredException) ]]; then - textFail "Subscription Required Exception trying to describe ECR repositories" + textFail "$regx: Subscription Required Exception trying to describe ECR repositories" "$regx" "$repo" continue fi if [[ ! -z "$LIST_ECR_REPOS" ]]; then for repo in $LIST_ECR_REPOS; do TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX) - $AWSCLI ecr get-repository-policy $PROFILE_OPT --region $region --repository-name $repo --query "policyText" --output text > $TEMP_POLICY_FILE 2>&1 + $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 "$region: $repo Access Denied for get-repository-policy" + textFail "$regx: $repo Access Denied for get-repository-policy" "$regx" "$repo" rm -f $TEMP_POLICY_FILE continue fi # https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html - "By default, only the repository owner has access to a repository." if [[ $(grep RepositoryPolicyNotFoundException $TEMP_POLICY_FILE) ]]; then - textPass "$region: $repo is not open" "$region" + textPass "$regx: $repo is not open" "$regx" "$repo" rm -f $TEMP_POLICY_FILE continue fi # check if the policy has Principal as * CHECK_ECR_REPO_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | jq '.Statement[]|select(.Effect=="Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")))') if [[ $CHECK_ECR_REPO_ALLUSERS_POLICY ]]; then - textFail "$region: $repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$region" + textFail "$regx: $repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" else - textPass "$region: $repo is not open" "$region" + textPass "$regx: $repo is not open" "$regx" "$repo" fi rm -f $TEMP_POLICY_FILE done else - textInfo "$region: No ECR repositories found" "$region" + textInfo "$regx: No ECR repositories found" "$regx" "$repo" fi done } diff --git a/checks/check_extra770 b/checks/check_extra770 index 7c52439b..c1e9694b 100644 --- a/checks/check_extra770 +++ b/checks/check_extra770 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra770="7.70" -CHECK_TITLE_extra770="[extra770] Check for internet facing EC2 instances with Instance Profiles attached (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra770="[extra770] Check for internet facing EC2 instances with Instance Profiles attached " CHECK_SCORED_extra770="NOT_SCORED" CHECK_TYPE_extra770="EXTRA" CHECK_SEVERITY_extra770="Medium" @@ -24,8 +24,7 @@ CHECK_DOC_extra770='https://aws.amazon.com/blogs/aws/aws-web-application-firewal CHECK_CAF_EPIC_extra770='Infrastructure Security' extra770(){ - # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" - textInfo "Looking for instances in all regions... " + # "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) if [[ $LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES ]];then @@ -33,7 +32,7 @@ extra770(){ INSTANCE_ID=$(echo $instance | awk '{ print $1; }') PUBLIC_IP=$(echo $instance | awk '{ print $2; }') INSTANCE_PROFILE=$(echo $instance | awk '{ print $3; }') - textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing with Instance Profile $INSTANCE_PROFILE" "$regx" + textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing with Instance Profile $INSTANCE_PROFILE" "$regx" "$INSTANCE_ID" done <<< "$LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES" else textPass "$regx: no Internet Facing EC2 Instances with Instance Profiles found" "$regx" diff --git a/checks/check_extra771 b/checks/check_extra771 index cffc6021..a2236c00 100644 --- a/checks/check_extra771 +++ b/checks/check_extra771 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra771="7.71" -CHECK_TITLE_extra771="[extra771] Check if S3 buckets have policies which allow WRITE access (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra771="[extra771] Check if S3 buckets have policies which allow WRITE access " CHECK_SCORED_extra771="NOT_SCORED" CHECK_TYPE_extra771="EXTRA" CHECK_SEVERITY_extra771="Critical" @@ -33,9 +33,9 @@ extra771(){ else BUCKET_POLICY_BAD_STATEMENTS=$(echo $BUCKET_POLICY_STATEMENTS | jq --arg arn "arn:${AWS_PARTITION}:s3:::$bucket" 'fromjson | .Statement[]|select(.Effect=="Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and (.Action|startswith("s3:Put") or startswith("s3:*")) and .Condition == null)') if [[ $BUCKET_POLICY_BAD_STATEMENTS != "" ]]; then - textFail "Bucket $bucket allows public write: $BUCKET_POLICY_BAD_STATEMENTS" + textFail "Bucket $bucket allows public write: $BUCKET_POLICY_BAD_STATEMENTS" "us-east-1" "$bucket" else - textPass "Bucket $bucket has S3 bucket policy which does not allow public write access" + textPass "Bucket $bucket has S3 bucket policy which does not allow public write access" "us-east-1" "$bucket" fi fi done diff --git a/checks/check_extra772 b/checks/check_extra772 index 2604662e..93b36041 100644 --- a/checks/check_extra772 +++ b/checks/check_extra772 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra772="7.72" -CHECK_TITLE_extra772="[extra772] Check if elastic IPs are unused (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra772="[extra772] Check if elastic IPs are unused " CHECK_SCORED_extra772="NOT_SCORED" CHECK_TYPE_extra772="EXTRA" CHECK_SEVERITY_extra772="Low" @@ -31,9 +31,9 @@ extra772(){ for eip in $EIP_LIST; do ASSOCIATION_ID=$(echo $EIP_DUMP | jq -r --arg i "$eip" '.Addresses[]|select(.AllocationId==$i)|.AssociationId') if [[ "$ASSOCIATION_ID" == "null" ]]; then - textFail "$region: EIP $eip is unused" $region + textFail "$region: EIP $eip is unused" "$region" "$eip" else - textPass "$region: EIP $eip is used" $region + textPass "$region: EIP $eip is used" "$region" "$eip" fi done else diff --git a/checks/check_extra773 b/checks/check_extra773 index 34a6cacc..7c168fcd 100644 --- a/checks/check_extra773 +++ b/checks/check_extra773 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra773="7.73" -CHECK_TITLE_extra773="[extra773] Check if CloudFront distributions are using WAF (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra773="[extra773] Check if CloudFront distributions are using WAF " CHECK_SCORED_extra773="NOT_SCORED" CHECK_TYPE_extra773="EXTRA" CHECK_SEVERITY_extra773="Medium" @@ -25,15 +25,15 @@ CHECK_DOC_extra773='https://docs.aws.amazon.com/waf/latest/developerguide/cloudf CHECK_CAF_EPIC_extra773='Infrastructure Security' extra773(){ - # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if CloudFront distributions have logging enabled " 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 WEB_ACL_ID=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --id "$dist" --query 'Distribution.DistributionConfig.WebACLId' --output text) if [[ $WEB_ACL_ID ]]; then - textPass "CloudFront distribution $dist is using AWS WAF web ACL $WEB_ACL_ID" + textPass "CloudFront distribution $dist is using AWS WAF web ACL $WEB_ACL_ID" "us-east-1" "$dist" else - textFail "CloudFront distribution $dist is not using AWS WAF web ACL" + textFail "CloudFront distribution $dist is not using AWS WAF web ACL" "us-east-1" "$dist" fi done else diff --git a/checks/check_extra775 b/checks/check_extra775 index 9d871b97..96d0d3b4 100644 --- a/checks/check_extra775 +++ b/checks/check_extra775 @@ -11,7 +11,7 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra775="7.75" -CHECK_TITLE_extra775="[extra775] Find secrets in EC2 Auto Scaling Launch Configuration (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra775="[extra775] Find secrets in EC2 Auto Scaling Launch Configuration " CHECK_SCORED_extra775="NOT_SCORED" CHECK_TYPE_extra775="EXTRA" CHECK_SEVERITY_extra775="Critical" @@ -29,7 +29,6 @@ extra775(){ mkdir $SECRETS_TEMP_FOLDER fi - textInfo "Looking for secrets in EC2 Auto Scaling Launch Configuration across all regions... (max 100 autoscaling_configurations per region use -m to increase it) " 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) if [[ $LIST_OF_EC2_AUTOSCALING ]];then @@ -44,11 +43,11 @@ extra775(){ if [[ $FILE_FORMAT_ASCII ]]; then FINDINGS=$(secretsDetector file $EC2_AUTOSCALING_USERDATA_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in $autoscaling_configuration" "$regx" + textPass "$regx: No secrets found in $autoscaling_configuration" "$regx" "$autoscaling_configuration" # delete file if nothing interesting is there rm -f $EC2_AUTOSCALING_USERDATA_FILE else - textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx" + textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx" "$autoscaling_configuration" # delete file to not leave trace, user must look at the autoscaling_configuration User Data rm -f $EC2_AUTOSCALING_USERDATA_FILE fi @@ -56,14 +55,14 @@ extra775(){ mv $EC2_AUTOSCALING_USERDATA_FILE $EC2_AUTOSCALING_USERDATA_FILE.gz ; gunzip $EC2_AUTOSCALING_USERDATA_FILE.gz FINDINGS=$(secretsDetector file $EC2_AUTOSCALING_USERDATA_FILE) if [[ $FINDINGS -eq 0 ]]; then - textPass "$regx: No secrets found in $autoscaling_configuration User Data" "$regx" + textPass "$regx: No secrets found in $autoscaling_configuration User Data" "$regx" "$autoscaling_configuration" rm -f $EC2_AUTOSCALING_USERDATA_FILE else - textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx" + textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx" "$autoscaling_configuration" fi fi else - textPass "$regx: No secrets found in $autoscaling_configuration User Data or it is empty" "$regx" + textPass "$regx: No secrets found in $autoscaling_configuration User Data or it is empty" "$regx" "$autoscaling_configuration" fi done else diff --git a/checks/check_extra776 b/checks/check_extra776 index 5bfe48a4..f234bb0b 100644 --- a/checks/check_extra776 +++ b/checks/check_extra776 @@ -26,7 +26,7 @@ # --image-id imageTag= CHECK_ID_extra776="7.76" -CHECK_TITLE_extra776="[extra776] Check if ECR image scan found vulnerabilities in the newest image version (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra776="[extra776] Check if ECR image scan found vulnerabilities in the newest image version " CHECK_SCORED_extra776="NOT_SCORED" CHECK_TYPE_extra776="EXTRA" CHECK_SEVERITY_extra776="Medium" @@ -54,28 +54,28 @@ extra776(){ if [[ ! -z "$LIST_ECR_REPOS" ]]; then IMAGE_SCAN_STATUS=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanStatus.status" 2>&1) if [[ $IMAGE_SCAN_STATUS == *"ScanNotFoundException"* ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG without a scan" "$region" + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG without a scan" "$region" "$repo" else if [[ $IMAGE_SCAN_STATUS == *"FAILED"* ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with scan status $IMAGE_SCAN_STATUS" "$region" + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with scan status $IMAGE_SCAN_STATUS" "$region" "$repo" else FINDINGS_COUNT=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanFindings.findingSeverityCounts" 2>&1) if [[ ! -z "$FINDINGS_COUNT" ]]; then SEVERITY_CRITICAL=$(echo "$FINDINGS_COUNT" | jq -r '.CRITICAL' ) if [[ "$SEVERITY_CRITICAL" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with CRITICAL ($SEVERITY_CRITICAL) findings" "$region" + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with CRITICAL ($SEVERITY_CRITICAL) findings" "$region" "$repo" fi SEVERITY_HIGH=$(echo "$FINDINGS_COUNT" | jq -r '.HIGH' ) if [[ "$SEVERITY_HIGH" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with HIGH ($SEVERITY_HIGH) findings" "$region" + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with HIGH ($SEVERITY_HIGH) findings" "$region" "$repo" fi SEVERITY_MEDIUM=$(echo "$FINDINGS_COUNT" | jq -r '.MEDIUM' ) if [[ "$SEVERITY_MEDIUM" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with MEDIUM ($SEVERITY_MEDIUM) findings" "$region" + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with MEDIUM ($SEVERITY_MEDIUM) findings" "$region" "$repo" fi SEVERITY_LOW=$(echo "$FINDINGS_COUNT" | jq -r '.LOW' ) if [[ "$SEVERITY_LOW" != "null" ]]; then - textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with LOW ($SEVERITY_LOW) findings" "$region" + textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with LOW ($SEVERITY_LOW) findings" "$region" fi SEVERITY_INFORMATIONAL=$(echo "$FINDINGS_COUNT" | jq -r '.INFORMATIONAL' ) if [[ "$SEVERITY_INFORMATIONAL" != "null" ]]; then diff --git a/checks/check_extra777 b/checks/check_extra777 index ffd79feb..f79d907e 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 (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra777="[extra777] Find VPC security groups with many ingress or egress rules " CHECK_SCORED_extra777="NOT_SCORED" CHECK_TYPE_extra777="EXTRA" CHECK_SEVERITY_extra777="Medium" @@ -29,7 +29,6 @@ CHECK_CAF_EPIC_extra777='Infrastructure Security' extra777(){ THRESHOLD=50 - textInfo "Looking for VPC security groups with more than ${THRESHOLD} rules across all regions... " for regx in ${REGIONS}; do SECURITY_GROUP_IDS=$(${AWSCLI} ec2 describe-security-groups \ @@ -58,7 +57,7 @@ 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}" + textFail "${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 3814d52c..63cb12cd 100644 --- a/checks/check_extra778 +++ b/checks/check_extra778 @@ -12,7 +12,7 @@ # specific language governing permissions and limitations under the License. CHECK_ID_extra778="7.78" -CHECK_TITLE_extra778="[extra778] Find VPC security groups with wide-open public IPv4 CIDR ranges (non-RFC1918) (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra778="[extra778] Find VPC security groups with wide-open public IPv4 CIDR ranges (non-RFC1918) " CHECK_SCORED_extra778="NOT_SCORED" CHECK_TYPE_extra778="EXTRA" CHECK_SEVERITY_extra778="Medium" @@ -27,7 +27,6 @@ CHECK_CAF_EPIC_extra778='Infrastructure Security' extra778(){ CIDR_THRESHOLD=24 RFC1918_REGEX="(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)" - textInfo "Looking for VPC security groups with wide-open (&1) if [[ $(echo "$DESCRIBE_TRAILS_CACHE" | grep AccessDenied) ]]; then - textFail "Access Denied trying to describe trails in $REGION" + textFail "$REGION: Access Denied trying to describe trails in $REGION" "$REGION" "$group" return fi @@ -63,7 +63,7 @@ check3x(){ for group in $CHECK_OK; do metric=${group#*:} group=${group%:*} - textPass "CloudWatch group $group found with metric filter $metric and alarms set" + textPass "$REGION: CloudWatch group $group found with metric filter $metric and alarms set" "$REGION" "$group" done fi if [[ $CHECK_WARN ]]; then @@ -72,15 +72,15 @@ check3x(){ *:*) metric=${group#*:} group=${group%:*} if [[ $pass_count == 0 ]]; then - textFail "CloudWatch group $group found with metric filter $metric but no alarms associated" + textFail "$REGION: CloudWatch group $group found with metric filter $metric but no alarms associated" "$REGION" "$group" else - textInfo "CloudWatch group $group found with metric filter $metric but no alarms associated" + textInfo "$REGION: CloudWatch group $group found with metric filter $metric but no alarms associated" "$REGION" "$group" fi ;; *) if [[ $pass_count == 0 ]]; then - textFail "CloudWatch group $group found but no metric filters or alarms associated" + textFail "$REGION: CloudWatch group $group found but no metric filters or alarms associated" "$REGION" "$group" else - textInfo "CloudWatch group $group found but no metric filters or alarms associated" + textInfo "$REGION: CloudWatch group $group found but no metric filters or alarms associated" "$REGION" "$group" fi ;; esac @@ -88,10 +88,10 @@ check3x(){ fi if [[ $CHECK_CROSS_ACCOUNT_WARN ]]; then for group in $CHECK_CROSS_ACCOUNT_WARN; do - textInfo "CloudWatch group $group is not in this account" + textInfo "$REGION: CloudWatch group $group is not in this account" "$REGION" "$group" done fi else - textFail "No CloudWatch group found for CloudTrail events" + textFail "$REGION: No CloudWatch group found for CloudTrail events" "$REGION" "$group" fi } diff --git a/include/check_creds_last_used b/include/check_creds_last_used index 4f8633b3..09c64632 100644 --- a/include/check_creds_last_used +++ b/include/check_creds_last_used @@ -69,23 +69,23 @@ check_passwords_used_in_last_days() { # "When password_enabled is set to TRUE and password_last_used is set to no_information, ensure password_last_changed is less than X days ago" if [[ "$days_since_password_last_changed" -ge "$max_days" ]]; then - textFail "User $user has never logged into the console since creation and their password not changed in the past ${max_days} days" + textFail "$REGION: User $user has never logged into the console since creation and their password not changed in the past ${max_days} days" "$REGION" "$user" else - textInfo "User $user has not logged into the console since creation" + textInfo "$REGION: User $user has not logged into the console since creation" "$REGION" "$user" fi else days_password_not_in_use=$(how_older_from_today "${last_login_date%T*}") # "For each user having password_enabled set to TRUE, ensure password_last_used_date is less than X days ago." if [[ "$days_password_not_in_use" -ge "$max_days" ]]; then - textFail "User $user has not logged into the console in the past ${max_days} days" + textFail "$REGION: User $user has not logged into the console in the past ${max_days} days" "$REGION" "$user" else - textPass "User $user has logged into the console in the past ${max_days} days" + textPass "$REGION: User $user has logged into the console in the past ${max_days} days" "$REGION" "$user" fi fi done else - textPass "No users found with password enabled" + textPass "$REGION: No users found with password enabled" "$REGION" "$user" fi } @@ -122,22 +122,22 @@ check_access_key_used_in_last_days() { # "When a user having an access_key_x_active (where x is 1 or 2) to TRUE and corresponding access_key_x_last_used_date is set to N/A, # ensure access_key_x_last_rotated is less than X days ago" if [[ "$days_since_access_key_rotated" -ge "$max_days" ]]; then - textFail "User $user has never used access key $access_key_name since creation and not rotated it in the past ${max_days} days" + textFail "$REGION: User $user has never used access key $access_key_name since creation and not rotated it in the past ${max_days} days" "$REGION" "$user" else - textInfo "User $user has not used access key $access_key_name since creation" + textInfo "$REGION: User $user has not used access key $access_key_name since creation" "$REGION" "$user" fi else days_since_access_key_used=$(how_older_from_today "${access_key_last_used_date%T*}") # "For each user having an access_key_1_active or access_key_2_active to TRUE, ensure the corresponding access_key_n_last_used_date is less than X days ago" if [[ "$days_since_access_key_used" -ge "$max_days" ]]; then - textFail "User $user has not used access key $access_key_name in the past ${max_days} days" + textFail "$REGION: User $user has not used access key $access_key_name in the past ${max_days} days" "$REGION" "$user" else - textPass "User $user has used access key $access_key_name in the past ${max_days} days" + textPass "$REGION: User $user has used access key $access_key_name in the past ${max_days} days" "$REGION" "$user" fi fi done else - textPass "No users found with access key $access_key_name enabled" + textPass "$REGION: No users found with access key $access_key_name enabled" "$REGION" "$user" fi } diff --git a/include/colors b/include/colors index dd8a8d20..d1f2afcb 100644 --- a/include/colors +++ b/include/colors @@ -67,7 +67,10 @@ fi printColorsCode(){ if [[ $MONOCHROME -eq 0 ]]; then - echo -e "\n$NORMAL Colors code for results: " - echo -e "$NOTICE INFO (Information)$NORMAL,$OK PASS (Recommended value)$NORMAL, $WARNING WARNING (Ignored by whitelist)$NORMAL, $BAD FAIL (Fix required)$NORMAL, $PURPLE Not Scored $NORMAL" + echo -e "\n$NORMAL Color code for results: " + echo -e " - $NOTICE INFO (Information)$NORMAL" + echo -e " - $OK PASS (Recommended value)$NORMAL" + echo -e " - $WARNING WARNING (Ignored by whitelist)$NORMAL" + echo -e " - $BAD FAIL (Fix required)$NORMAL" fi } diff --git a/include/credentials_report b/include/credentials_report index 8a98e2de..3741e89a 100644 --- a/include/credentials_report +++ b/include/credentials_report @@ -13,7 +13,7 @@ # Generate Credential Report genCredReport() { - textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" + textTitle "" "Generating AWS IAM Credential Report..." for i in $(seq 1 60); do GENERATECREDENTIALREPORTOUTPUT=$($AWSCLI iam generate-credential-report --output text --query 'State' $PROFILE_OPT --region $REGION 2>&1) if [[ $(echo "$GENERATECREDENTIALREPORTOUTPUT" | grep AccessDenied) ]]; then diff --git a/include/csv_header b/include/csv_header index 7a867815..1c01f93d 100644 --- a/include/csv_header +++ b/include/csv_header @@ -15,6 +15,6 @@ printCsvHeader() { # >&2 echo "" # >&2 echo "Generating \"${SEP}\" delimited report on stdout for profile $PROFILE, account $ACCOUNT_NUM" - echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}CHECK_RESULT${SEP}ITEM_SCORED${SEP}ITEM_LEVEL${SEP}TITLE_TEXT${SEP}CHECK_RESULT_EXTENDED${SEP}CHECK_ASFF_COMPLIANCE_TYPE${SEP}CHECK_SEVERITY${SEP}CHECK_SERVICENAME${SEP}CHECK_ASFF_RESOURCE_TYPE${SEP}CHECK_ASFF_TYPE${SEP}CHECK_RISK${SEP}CHECK_REMEDIATION${SEP}CHECK_DOC${SEP}CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV + echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}CHECK_RESULT${SEP}ITEM_SCORED${SEP}ITEM_LEVEL${SEP}TITLE_TEXT${SEP}CHECK_RESULT_EXTENDED${SEP}CHECK_ASFF_COMPLIANCE_TYPE${SEP}CHECK_SEVERITY${SEP}CHECK_SERVICENAME${SEP}CHECK_ASFF_RESOURCE_TYPE${SEP}CHECK_ASFF_TYPE${SEP}CHECK_RISK${SEP}CHECK_REMEDIATION${SEP}CHECK_DOC${SEP}CHECK_CAF_EPIC${SEP}CHECK_RESOURCE_ID${SEP}PROWLER_START_TIME" >> ${OUTPUT_FILE_NAME}.$EXTENSION_CSV # echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES${SEP}COMPLIANCE${SEP}SEVERITY${SEP}SERVICENAME" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV } diff --git a/include/html_report b/include/html_report index 42db8626..c1097470 100644 --- a/include/html_report +++ b/include/html_report @@ -25,35 +25,19 @@ addHtmlHeader() { + - + + - - - - Prowler - AWS Security Assessments @@ -144,7 +128,6 @@ addHtmlHeader() { - @@ -152,12 +135,13 @@ addHtmlHeader() { - - + + - - - + + + + @@ -179,16 +163,50 @@ addHtmlFooter() { - - - - - - + + + + \$(document).ready(function(){ + + // Initialise the table with 50 rows, and some search/filtering panes + \$('#findingsTable').DataTable( { + lengthMenu: [ [50, 100, -1], [50, 100, "All"] ], + searchPanes: { + cascadePanes: true, + viewTotal: true + }, + dom: 'Plfrtip', + columnDefs: [ + { + searchPanes: { + show: false + }, + // Hide Compliance, Check ID (in favour of Check Title), CAF Epic, Risk, Remediation, Link + targets: [4, 6, 9, 10, 11, 12] + } + ] + }); + + var maxLength = 30; + \$(".show-read-more").each(function(){ + var myStr = \$(this).text(); + if(\$.trim(myStr).length > maxLength){ + var newStr = myStr.substring(0, maxLength); + var removedStr = myStr.substring(maxLength, \$.trim(myStr).length); + \$(this).empty().html(newStr); + \$(this).append(' read more...'); + \$(this).append('' + removedStr + ''); + } + }); + \$(".read-more").click(function(){ + \$(this).siblings(".more-text").contents().unwrap(); + \$(this).remove(); + }); + }); + + EOF diff --git a/include/outputs b/include/outputs index 9d51f823..830404d2 100644 --- a/include/outputs +++ b/include/outputs @@ -15,12 +15,28 @@ EXTENSION_CSV="csv" EXTENSION_JSON="json" -EXTENSION_ASFF="asff-json" +EXTENSION_ASFF="asff.json" EXTENSION_TEXT="txt" EXTENSION_HTML="html" OUTPUT_DATE=$(date -u +"%Y%m%d%H%M%S") -OUTPUT_DIR="${PROWLER_DIR}/output" # default output if none -OUTPUT_FILE_NAME="${OUTPUT_DIR}/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}" +OUTPUT_DIR="${PROWLER_DIR}/output" # default output if none +if [[ $OUTPUT_DIR_CUSTOM ]]; then + # output mode has to be set to other than text + if [[ ! " ${MODES[@]} " =~ " text " || ${check_id} == 7.1 || ${check_id} == 7.74 ]]; then + if [[ ! -d $OUTPUT_DIR_CUSTOM ]]; then + echo "$OPTRED ERROR!$OPTNORMAL directory \"$OUTPUT_DIR_CUSTOM\" does not exist." + exit 1 + else + OUTPUT_DIR=$OUTPUT_DIR_CUSTOM + fi + else + echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) has to be set as well. Use -h for help." + exit 1 + fi +fi +if [ -z ${OUTPUT_FILE_NAME+x} ]; then + OUTPUT_FILE_NAME="${OUTPUT_DIR}/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}" +fi HTML_LOGO_URL="https://github.com/toniblyx/prowler/" HTML_LOGO_IMG="https://github.com/toniblyx/prowler/raw/2.4/util/html/prowler-logo-new.png" TIMESTAMP=$(get_iso8601_timestamp) @@ -32,19 +48,19 @@ PROWLER_PARAMETERS=$@ # $ACCOUNT_NUM AWS Account ID # $REPREGION AWS region scanned # $TITLE_ID Numeric identifier of each check (1.2, 2.3, etc), originally based on CIS checks. -# $CHECK_RESULT values can be PASS, FAIL, INFO or WARNING if whitelisted +# $CHECK_RESULT values can be PASS, FAIL, INFO or WARNING if whitelisted # $ITEM_SCORED corresponds to CHECK_SCORED, values can be Scored/Not Scored. This is CIS only, will be deprecated in Prowler. # $ITEM_LEVEL corresponds to CHECK_TYPE_ currently only for CIS Level 1, CIS Level 2 and Extras (all checks not part of CIS) -# $TITLE_TEXT corresponds to CHECK_TITLE_ shows title of each check +# $TITLE_TEXT corresponds to CHECK_TITLE_ shows title of each check # $CHECK_RESULT_EXTENDED shows response of each check per resource like sg-123438 is open! -# $CHECK_ASFF_COMPLIANCE_TYPE specify type from taxonomy https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html +# $CHECK_ASFF_COMPLIANCE_TYPE specify type from taxonomy https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html # $CHECK_SEVERITY severity Low, Medium, High, Critical # $CHECK_SERVICENAME AWS service name short name # $CHECK_ASFF_RESOURCE_TYPE values from https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#asff-resources # $CHECK_ASFF_TYPE generic type from taxonomy here https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html -# $CHECK_RISK text about risk -# $CHECK_REMEDIATION text about remediation -# $CHECK_DOC link to related documentation +# $CHECK_RISK text about risk +# $CHECK_REMEDIATION text about remediation +# $CHECK_DOC link to related documentation # $CHECK_CAF_EPIC it can be Logging and Monitoring, IAM, Data Protection, Infrastructure Security. Incident Response is not included since CAF has not specific checks on it logs enablement are part of Logging and Monitoring. # Ensure that output directory always exists when -M is used @@ -56,6 +72,11 @@ if [[ $MODE ]];then fi fi +# textInfo "HTML report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_HTML" +# textInfo "JSON ASFF report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_ASFF" +# textInfo "CSV report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_CSV" +# textInfo "JSON report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_JSON" + if [[ $PROFILE == "" ]];then PROFILE="ENV" fi @@ -63,6 +84,7 @@ fi textPass(){ CHECK_RESULT="PASS" CHECK_RESULT_EXTENDED="$1" + CHECK_RESOURCE_ID="$3" if [[ "$QUIET" == 1 ]]; then return @@ -75,27 +97,28 @@ textPass(){ REPREGION=$REGION fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID${SEP}$PROWLER_START_TIME" >> ${OUTPUT_FILE_NAME}.$EXTENSION_CSV fi if [[ "${MODES[@]}" =~ "json" ]]; then - generateJsonOutput "$1" "Pass" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_JSON + generateJsonOutput "$1" "Pass" "$CHECK_RESOURCE_ID" >> ${OUTPUT_FILE_NAME}.$EXTENSION_JSON fi if [[ "${MODES[@]}" =~ "json-asff" ]]; then - JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED") - echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF + JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED" "$CHECK_RESOURCE_ID") + echo "${JSON_ASFF_OUTPUT}" >> $OUTPUT_FILE_NAME.$EXTENSION_ASFF if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then - sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}" + sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}" fi fi if is_junit_output_enabled; then output_junit_success "$1" fi if [[ "${MODES[@]}" =~ "mono" ]]; then - echo " $OK PASS!$NORMAL $1" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT + echo " $OK PASS!$NORMAL $1" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT fi - if [[ "${MODES[@]}" =~ "text" || "${MODES[@]}" =~ "mono" ]]; then + # if [[ "${MODES[@]}" =~ "text" || "${MODES[@]}" =~ "mono" ]]; then + # runs showing console output no mater what output is selected echo " $OK PASS!$NORMAL $1" - fi + # fi if [[ "${MODES[@]}" =~ "html" ]]; then generateHtmlOutput "$1" "PASS" fi @@ -104,6 +127,7 @@ textPass(){ textInfo(){ CHECK_RESULT="INFO" CHECK_RESULT_EXTENDED="$1" + CHECK_RESOURCE_ID="$3" if [[ "$QUIET" == 1 ]]; then return @@ -115,22 +139,22 @@ textInfo(){ REPREGION=$REGION fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID${SEP}$PROWLER_START_TIME" >> ${OUTPUT_FILE_NAME}.$EXTENSION_CSV fi if [[ "${MODES[@]}" =~ "json" ]]; then - generateJsonOutput "$1" "Info" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} + generateJsonOutput "$1" "Info" "$CHECK_RESOURCE_ID" >> ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} fi if is_junit_output_enabled; then output_junit_info "$1" fi if [[ "${MODES[@]}" =~ "mono" ]]; then - echo " $NOTICE INFO! $1 $NORMAL" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT + echo " $NOTICE INFO! $1 $NORMAL" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT fi - if [[ "${MODES[@]}" =~ "text" ]]; then + # if [[ "${MODES[@]}" =~ "text" ]]; then echo " $NOTICE INFO! $1 $NORMAL" - fi + # fi if [[ "${MODES[@]}" =~ "html" ]]; then - generateHtmlOutput "$1" "INFO" + generateHtmlOutput "$1" "INFO" "$CHECK_RESOURCE_ID" fi } @@ -162,6 +186,7 @@ textFail(){ CHECK_RESULT=$level CHECK_RESULT_EXTENDED="$1" + CHECK_RESOURCE_ID="$3" if [[ $2 ]]; then REPREGION=$2 @@ -170,14 +195,14 @@ textFail(){ fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID${SEP}$PROWLER_START_TIME" >> ${OUTPUT_FILE_NAME}.$EXTENSION_CSV fi if [[ "${MODES[@]}" =~ "json" ]]; then - generateJsonOutput "$1" "${level}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} + generateJsonOutput "$1" "${level}" "$CHECK_RESOURCE_ID">> ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} fi if [[ "${MODES[@]}" =~ "json-asff" ]]; then - JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}") - echo "${JSON_ASFF_OUTPUT}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF} + JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}" "$CHECK_RESOURCE_ID") + echo "${JSON_ASFF_OUTPUT}" >> ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF} if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}" fi @@ -190,74 +215,78 @@ textFail(){ fi fi if [[ "${MODES[@]}" =~ "mono" ]]; then - echo " $colorcode ${level}! $1 $NORMAL" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT + echo " $colorcode ${level}! $1 $NORMAL" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT fi - if [[ "${MODES[@]}" =~ "text" ]]; then + # if [[ "${MODES[@]}" =~ "text" ]]; then echo " $colorcode ${level}! $1 $NORMAL" - fi + # fi if [[ "${MODES[@]}" =~ "html" ]]; then - generateHtmlOutput "$1" "${level}" + generateHtmlOutput "$1" "${level}" "$CHECK_RESOURCE_ID" fi } textTitle(){ CHECKS_COUNTER=$((CHECKS_COUNTER+1)) - TITLE_ID=$1 + TITLE_ID="$1" if [[ $NUMERAL ]]; then # Left-pad the check ID with zeros to simplify sorting, e.g. 1.1 -> 1.01 TITLE_ID=$(awk -F'.' '{ printf "%d.%02d", $1, $2 }' <<< "$TITLE_ID") fi TITLE_TEXT=$2 + CHECK_SERVICENAME="$MAGENTA$3$NORMAL" + local CHECK_SEVERITY="$BROWN[$4]$NORMAL" - case "$3" in - 0|No|NOT_SCORED) - ITEM_SCORED="Not Scored" - ;; - 1|Yes|SCORED) - ITEM_SCORED="Scored" - ;; - *) - ITEM_SCORED="Unspecified" - ;; - esac + # case "$3" in + # 0|No|NOT_SCORED) + # ITEM_SCORED="Not Scored" + # ;; + # 1|Yes|SCORED) + # ITEM_SCORED="Scored" + # ;; + # *) + # ITEM_SCORED="Unspecified" + # ;; + # esac - case "$4" in - LEVEL1) ITEM_LEVEL="Level 1";; - LEVEL2) ITEM_LEVEL="Level 2";; - EXTRA) ITEM_LEVEL="Extra";; - SUPPORT) ITEM_LEVEL="Support";; - *) ITEM_LEVEL="Unspecified or Invalid";; - esac + # case "$4" in + # LEVEL1) ITEM_LEVEL="Level 1";; + # LEVEL2) ITEM_LEVEL="Level 2";; + # EXTRA) ITEM_LEVEL="Extra";; + # SUPPORT) ITEM_LEVEL="Support";; + # *) ITEM_LEVEL="Unspecified or Invalid";; + # esac local group_ids - if [[ -n "$5" ]]; then - group_ids="$CYAN [$5] $NORMAL" - fi + # if [[ -n "$4" ]]; then + group_ids="$CYAN[$5]$NORMAL" + # fi - if [[ "${MODES[@]}" =~ "csv" ]]; then - >&2 echo "$TITLE_ID $TITLE_TEXT" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} - elif [[ "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then - : - else - if [[ "$ITEM_SCORED" == "Scored" ]]; then - echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT $6 $group_ids " - else - echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $6 $NORMAL $group_ids " - fi - fi + # if [[ "${MODES[@]}" =~ "csv" ]]; then + # >&2 echo "$TITLE_ID $TITLE_TEXT" >> ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} + # elif [[ "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then + # : + # else + # # if [[ "$ITEM_SCORED" == "Scored" ]]; then + # echo -e "$TITLE_ID $CHECK_SERVICENAME $TITLE_TEXT $CHECK_SEVERITY $group_ids " + echo -e "$TITLE_ID $TITLE_TEXT - $CHECK_SERVICENAME $CHECK_SEVERITY" + # # else + # # echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $6 $NORMAL $group_ids " + # # fi + # fi } generateJsonOutput(){ local message=$1 local status=$2 + local resource_id=$3 jq -M -c \ --arg PROFILE "$PROFILE" \ --arg ACCOUNT_NUM "$ACCOUNT_NUM" \ --arg TITLE_TEXT "$TITLE_TEXT" \ --arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \ --arg STATUS "$status" \ - --arg SEVERITY "$CHECK_SEVERITY" \ + --arg SEVERITY "$(echo $CHECK_SEVERITY | sed 's/[][]//g')" \ --arg SCORED "$ITEM_SCORED" \ --arg ITEM_LEVEL "$ITEM_LEVEL" \ --arg TITLE_ID "$TITLE_ID" \ @@ -265,6 +294,11 @@ generateJsonOutput(){ --arg TYPE "$CHECK_ASFF_COMPLIANCE_TYPE" \ --arg TIMESTAMP "$(get_iso8601_timestamp)" \ --arg SERVICENAME "$CHECK_SERVICENAME" \ + --arg CHECK_CAF_EPIC "$CHECK_CAF_EPIC" \ + --arg CHECK_RISK "$CHECK_RISK" \ + --arg CHECK_REMEDIATION "$CHECK_REMEDIATION" \ + --arg CHECK_DOC "$CHECK_DOC" \ + --arg CHECK_RESOURCE_ID "$resource_id" \ -n '{ "Profile": $PROFILE, "Account Number": $ACCOUNT_NUM, @@ -278,7 +312,12 @@ generateJsonOutput(){ "Region": $REPREGION, "Timestamp": $TIMESTAMP, "Compliance": $TYPE, - "Service": $SERVICENAME + "Service": $SERVICENAME, + "CAF Epic": $CHECK_CAF_EPIC, + "Risk": $CHECK_RISK, + "Remediation": $CHECK_REMEDIATION, + "Doc link": $CHECK_DOC, + "Resource ID": $CHECK_RESOURCE_ID }' } @@ -287,17 +326,24 @@ generateJsonAsffOutput(){ # Replace any successive non-conforming characters with a single underscore local message=$1 local status=$2 - + + #Checks to determine if the rule passes in a resource name that prowler uses to track the AWS Resource for whitelisting purposes + if [[ -z $3 ]]; then + local resource_id="NONE_PROVIDED" + else + local resource_id=$3 + fi + if [[ "$status" == "FAIL" ]]; then status="FAILED" fi jq -M -c \ --arg ACCOUNT_NUM "$ACCOUNT_NUM" \ - --arg TITLE_TEXT "$TITLE_TEXT" \ - --arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \ + --arg TITLE_TEXT "$CHECK_SERVICENAME.$TITLE_TEXT" \ + --arg MESSAGE "$(echo -e "${message}")" \ --arg UNIQUE_ID "$(LC_ALL=C echo -e -n "${message}" | tr -cs '[:alnum:]._~-' '_')" \ --arg STATUS "$status" \ - --arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }')" \ + --arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }' | sed 's/[][]//g')" \ --arg TITLE_ID "$TITLE_ID" \ --arg CHECK_ID "$CHECK_ID" \ --arg TYPE "$CHECK_ASFF_COMPLIANCE_TYPE" \ @@ -307,6 +353,7 @@ generateJsonAsffOutput(){ --arg TIMESTAMP "$(get_iso8601_timestamp)" \ --arg PROWLER_VERSION "$PROWLER_VERSION" \ --arg AWS_PARTITION "$AWS_PARTITION" \ + --arg CHECK_RESOURCE_ID "$resource_id" \ -n '{ "SchemaVersion": "2018-10-08", "Id": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)", @@ -314,7 +361,8 @@ generateJsonAsffOutput(){ "RecordState": "ACTIVE", "ProductFields": { "ProviderName": "Prowler", - "ProviderVersion": $PROWLER_VERSION + "ProviderVersion": $PROWLER_VERSION, + "ProwlerResourceName": $CHECK_RESOURCE_ID }, "GeneratorId": "prowler-\($CHECK_ID)", "AwsAccountId": $ACCOUNT_NUM, @@ -332,7 +380,7 @@ generateJsonAsffOutput(){ "Resources": [ { "Type": $RESOURCE_TYPE, - "Id": "AWS::::Account:\($ACCOUNT_NUM)", + "Id": $CHECK_RESOURCE_ID, "Partition": $AWS_PARTITION, "Region": $REPREGION } @@ -341,82 +389,44 @@ generateJsonAsffOutput(){ "Status": $STATUS, "RelatedRequirements": [ $COMPLIANCE_RELATED_REQUIREMENTS ] } + }' } generateHtmlOutput(){ local message=$1 local status=$2 + if [[ $status == "INFO" ]];then - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + local ROW_CLASS='table-info' fi if [[ $status == "PASS" ]];then - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + local ROW_CLASS='p-3 mb-2 bg-success-custom' fi if [[ $status == "FAIL" ]];then - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + local ROW_CLASS='table-danger' fi - if [[ $status == "WARNING" ]];then - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML - echo ''>> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + if [[ $status == "WARN" ]];then + local ROW_CLASS='table-warning' fi -} \ No newline at end of file + + local CHECK_SEVERITY="$(echo $CHECK_SEVERITY | sed 's/[][]//g')" + + echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ' ' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML +} diff --git a/include/outputs_bucket b/include/outputs_bucket new file mode 100644 index 00000000..f89a7fd4 --- /dev/null +++ b/include/outputs_bucket @@ -0,0 +1,57 @@ +#!/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. + +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 + # 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 + else + echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) has to be set as well. Use -h for help." + exit 1 + fi +fi + +copyToS3(){ + # Prowler will copy each format to its own folder in S3, that is for better handling + # 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 \ + 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 \ + 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 \ + 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 \ + s3://$OUTPUT_BUCKET/json-asff/ --acl bucket-owner-full-control + fi + fi +} \ No newline at end of file diff --git a/include/scoring b/include/scoring index b6fc7f08..3023d395 100644 --- a/include/scoring +++ b/include/scoring @@ -22,7 +22,7 @@ scoring(){ # TOTAL_RESOURCES=$(awk "BEGIN {print $FAIL_COUNTER+$PASS_COUNTER; exit}") TOTAL_RESOURCES=$(($FAIL_COUNTER + $PASS_COUNTER)) - # Score is % of passed compared to failures. The higher score, the better + # Score is % of passed compared to failures. The higher the better PROWLER_SCORE=$(( $PASS_COUNTER * 100 / $TOTAL_RESOURCES )) if [[ $SCORING == "1" ]]; then @@ -47,7 +47,7 @@ scoring(){ echo -e "$BLUE------------------------------------------------------------------ $NORMAL" echo -e " Checks Performed =$NOTICE $CHECKS_COUNTER $NORMAL" echo -e "$BLUE------------------------------------------------------------------ $NORMAL" - echo -e " * the highest the better (0 to 100)$NORMAL" + echo -e " * the higher the better (0 to 100)$NORMAL" echo -e " Prowler scoring uses any check, including CIS not scored checks$NORMAL" fi if [[ "${MODES[@]}" =~ "html" ]]; then diff --git a/include/whoami b/include/whoami index a2fa3ce2..a7c6256e 100644 --- a/include/whoami +++ b/include/whoami @@ -29,8 +29,9 @@ case "$REGION" in ;; esac -GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --region $REGION_FOR_STS 2>&1) -if [[ $(echo "$GETCALLER" | grep 'Unable') ]]; then +GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --output json --region $REGION_FOR_STS 2>&1) +ret=$? +if [[ $ret -ne 0 ]]; then if [[ $PRINTCHECKSONLY || $PRINTGROUPSONLY ]]; then echo Listing... else diff --git a/prowler b/prowler index 8d129916..879f73b9 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.4.0-07042021 +PROWLER_VERSION=2.5.0-12August2021 PROWLER_DIR=$(dirname "$0") REGION="" @@ -45,7 +45,7 @@ SEP=',' KEEPCREDREPORT=0 EXITCODE=0 SEND_TO_SECURITY_HUB=0 -SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) +PROWLER_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) TITLE_ID="" TITLE_TEXT="CALLER ERROR - UNSET TITLE" WHITELIST_FILE="" @@ -74,7 +74,7 @@ USAGE: -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 - (i.e.: us-west-1) + (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). @@ -100,13 +100,18 @@ USAGE: -w whitelist file. See whitelist_sample.txt for reference and format (i.e.: whitelist_sample.txt) -N Shoadan API key used by check extra7102. + -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 -V show version number & exit -h this help " exit } -while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:" OPTION; do +while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:F:" OPTION; do case $OPTION in h ) usage @@ -190,6 +195,15 @@ while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:" OPTION; do N ) SHODAN_API_KEY=$OPTARG ;; + o ) + OUTPUT_DIR_CUSTOM=$OPTARG + ;; + B ) + OUTPUT_BUCKET=$OPTARG + ;; + F ) + OUTPUT_FILE_NAME=$OPTARG + ;; : ) echo "" echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument" @@ -243,6 +257,7 @@ unset AWS_DEFAULT_OUTPUT . $PROWLER_DIR/include/csv_header . $PROWLER_DIR/include/banner . $PROWLER_DIR/include/html_report +. $PROWLER_DIR/include/outputs_bucket . $PROWLER_DIR/include/outputs . $PROWLER_DIR/include/credentials_report . $PROWLER_DIR/include/scoring @@ -295,7 +310,8 @@ TOTAL_CHECKS=($(echo "${TOTAL_CHECKS[*]}" | tr ' ' '\n' | awk '!seen[$0]++' | so get_regions() { # Get list of regions based on include/whoami REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' --output text $PROFILE_OPT --region $REGION_FOR_STS --region-names $FILTERREGION 2>&1) - if [[ $(echo "$REGIONS" | grep 'AccessDenied\|UnauthorizedOperation') ]]; then + ret=$? + if [[ $ret -ne 0 ]]; then echo "$OPTRED Access Denied trying to describe regions! Review permissions as described here: https://github.com/toniblyx/prowler/#requirements-and-installation $OPTNORMAL" EXITCODE=1 exit $EXITCODE @@ -310,25 +326,30 @@ show_check_title() { local check_scored=CHECK_SCORED_$1 local check_type=CHECK_TYPE_$1 local check_asff_compliance_type=CHECK_ASFF_COMPLIANCE_TYPE_$1 + local check_severity=CHECK_SEVERITY_$1 + local check_servicename=CHECK_SERVICENAME_$1 local group_ids local group_index + local check_name # If requested ($2 is any non-null value) iterate all GROUP_CHECKS and produce a comma-separated list of all # the GROUP_IDs that include this particular check if [[ -n "$2" ]]; then for group_index in "${!GROUP_ID[@]}"; do - if [[ "${GROUP_CHECKS[$group_index]}" =~ "$1" ]]; then - if [[ -n "$group_ids" ]]; then - group_ids+=", " + for check_name in $(echo "${GROUP_CHECKS[$group_index]}" | sed "s/,/ /g");do + if [[ "$check_name" == "$1" ]]; then + if [[ -n "$group_ids" ]]; then + group_ids+=", " + fi + group_ids+="${GROUP_ID[$group_index]}" fi - group_ids+="${GROUP_ID[$group_index]}" - fi + done done fi # This shows ASFF_COMPLIANCE_TYPE if group used is ens, this si used to show ENS compliance ID control, can be used for other compliance groups as well. if [[ ${GROUP_ID_READ} == "ens" ]];then textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids" "(${!check_asff_compliance_type})" else - textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids" + textTitle "${!check_id}" "${!check_title}" "${!check_servicename}" "${!check_severity}" "$group_ids" fi } @@ -336,7 +357,7 @@ show_check_title() { show_group_title() { # when csv mode is used, no group title is shown if [[ "$MODE" != "csv" ]]; then - textTitle "${GROUP_NUMBER[$1]}" "${GROUP_TITLE[$1]}" "NOT_SCORED" "SUPPORT" + textTitle "${GROUP_NUMBER[$1]}" "${GROUP_TITLE[$1]}" fi } @@ -344,7 +365,7 @@ show_group_title() { execute_check() { if [[ $ACCOUNT_TO_ASSUME ]]; then - # Following logic looks for time remaining in the session and review it + # 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) @@ -357,7 +378,7 @@ execute_check() { fi fi - CHECK_ID="$1" + CHECK_ID="$1" # See if this is an alternate name for a check # for example, we might have been passed 1.01 which is another name for 1.1 @@ -370,7 +391,7 @@ execute_check() { local asff_compliance_type_var=CHECK_ASFF_COMPLIANCE_TYPE_$1 CHECK_ASFF_COMPLIANCE_TYPE="${!asff_compliance_type_var:-Software and Configuration Checks}" - + # See if this check defines an ASFF Resource Type, if so, use this, falling back to a sane default # For a list of Resource Types, see: https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#asff-resources local asff_resource_type_var=CHECK_ASFF_RESOURCE_TYPE_$1 @@ -559,9 +580,9 @@ get_all_checks_without_exclusion() { } ### All functions defined above ... run the workflow -if [[ " ${MODES[@]} " =~ " mono " || " ${MODES[@]} " =~ " text " ]]; then +#if [[ " ${MODES[@]} " =~ " mono " || " ${MODES[@]} " =~ " text " ]]; then prowlerBanner -fi +#fi # List only check tittles if [[ $PRINTCHECKSONLY == "1" ]]; then @@ -607,6 +628,7 @@ if [[ $GROUP_ID_READ ]];then fi cleanTemp scoring + copyToS3 exit $EXITCODE else textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." @@ -634,6 +656,7 @@ if [[ $CHECK_ID ]];then if [[ "${MODES[@]}" =~ "html" ]]; then addHtmlFooter >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML fi + copyToS3 cleanTemp exit $EXITCODE fi @@ -643,8 +666,10 @@ execute_all if [[ "${MODES[@]}" =~ "html" ]]; then addHtmlFooter >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML fi + scoring cleanTemp +copyToS3 if [[ $ACCOUNT_TO_ASSUME ]]; then # unset env variables with assumed role credentials diff --git a/util/Dockerfile b/util/Dockerfile index f7a5ee67..6fbed17c 100644 --- a/util/Dockerfile +++ b/util/Dockerfile @@ -1,13 +1,13 @@ -FROM alpine:3.9 +FROM alpine:3.13 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 && \ + apk --update --no-cache add python3 bash curl jq file coreutils py3-pip && \ pip3 install --upgrade pip && \ - pip install awscli boto3 detect-secrets + pip3 install awscli boto3 detect-secrets WORKDIR /prowler diff --git a/util/cloudshell/README.md b/util/cloudshell/README.md new file mode 100644 index 00000000..21c3ac0a --- /dev/null +++ b/util/cloudshell/README.md @@ -0,0 +1,57 @@ +# ShortCut script: run Prowler and ScoutSuite in Customer's environment using AWS CloudShell + +### Use Case: + +Customers look to use multiple auditing tools in order to provide quick assessments about their AWS environments. These tools allow for reports to be generated for review by the customer and appropriate teams, which in turns helps them begin security remediation efforts. + +Prowler and ScoutSuite are two publicly available security auditing tools that provide comprehensive reports for customers using AWS. + +ShortCut is a mechanism for customers to use to run both Prowler and ScoutSuite within an AWS account, using AWS CloudShell. When customers use ShortCut, this allows for customers to quickly perform an audit on their environment, without having to provision IAM Access Keys or EC2 instances. + +### Prerequisites: + +Note: The current version of this script is ran in a single account. + +In order to use CloudShell, the customer will need the following permissions within their AWS Account: +``` +cloudshell:* +``` + +In addition, the following IAM Policies are needed in order to run ScoutSuite & Prowler: +``` +arn:aws:iam::aws:policy/SecurityAudit +arn:aws:iam::aws:policy/job-function/ViewOnlyAccess +``` + +### Instructions +1. Log into the AWS Console +2. Go to AWS CloudShell. There's a screenshot of the AWS CloudShell icon below, or if you're logged into AWS already, you can click this link: console.aws.amazon.com/cloudshell + +![Alt text](screenshots/cloudshell_icon.png) + +3. Once the session begins, upload the shortcut.sh file into the AWS CloudShell session by selecting Actions -> Upload File. + +![Alt text](screenshots/action_upload_icon.png) + +4. Once the file is uploaded, run the following command within your AWS CloudShell session: +``` +bash shortcut.sh +``` +5. The results for Prowler and ScoutSuite will be located in the following directory: +``` +/home/cloudshell-user/-results +``` +6. You can check the status of each screen session by typing the following commands: +``` +# Prowler: +screen -r prowler +# ScoutSuite +screen -r scoutsuite +``` +7. To download the results from AWS CloudShell, select Actions -> Download File. + +![Alt text](screenshots/action_download_icon.png) + +8. In the Download File prompt, use the file path and file name to download the results. + +![Alt text](screenshots/download_prompt.png) \ No newline at end of file diff --git a/util/cloudshell/screenshots/action_download_icon.png b/util/cloudshell/screenshots/action_download_icon.png new file mode 100644 index 00000000..f8bed6ed Binary files /dev/null and b/util/cloudshell/screenshots/action_download_icon.png differ diff --git a/util/cloudshell/screenshots/action_upload_icon.png b/util/cloudshell/screenshots/action_upload_icon.png new file mode 100644 index 00000000..8784053a Binary files /dev/null and b/util/cloudshell/screenshots/action_upload_icon.png differ diff --git a/util/cloudshell/screenshots/cloudshell_icon.png b/util/cloudshell/screenshots/cloudshell_icon.png new file mode 100644 index 00000000..4c520ac4 Binary files /dev/null and b/util/cloudshell/screenshots/cloudshell_icon.png differ diff --git a/util/cloudshell/screenshots/download_prompt.png b/util/cloudshell/screenshots/download_prompt.png new file mode 100644 index 00000000..fd5eac35 Binary files /dev/null and b/util/cloudshell/screenshots/download_prompt.png differ diff --git a/util/cloudshell/shortcut.sh b/util/cloudshell/shortcut.sh new file mode 100644 index 00000000..063b3686 --- /dev/null +++ b/util/cloudshell/shortcut.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# ShortCut - Run Prowler and ScoutSuite in Customer's environment using AWS CloudShell +# DozerCat - Team DragonCat - AWS + +# Package Prerequisites +sudo yum update -y +sudo yum install python3 -y +sudo yum install screen -y +sudo yum install zip -y + +# Variable and Environment Prerequisites +account=$(aws sts get-caller-identity | jq --raw-output '.Account') +mkdir ${account}-results + +# Prowler +cd ~ +git clone https://github.com/toniblyx/prowler +pip3 install detect-secrets --user +cd prowler +screen -dmS prowler sh -c "./prowler -M csv,html;cd ~;zip -r ${account}-results/prowler-${account}.zip /home/cloudshell-user/prowler/output" + +# ScoutSuite +cd ~ +git clone https://github.com/nccgroup/ScoutSuite +cd ScoutSuite +sudo yum install python-pip -y +sudo pip install virtualenv +virtualenv -p python3 venv +source venv/bin/activate +pip install -r requirements.txt +sleep 2 +screen -dmS scoutsuite sh -c "python scout.py aws;cd ~;zip -r ${account}-results/scoutsuite-${account}.zip /home/cloudshell-user/ScoutSuite/scoutsuite-report" + +# Check on screen sessions +screen -ls diff --git a/util/codebuild/codebuild-prowler-audit-account-cfn.yaml b/util/codebuild/codebuild-prowler-audit-account-cfn.yaml index 1022da6e..1af61a7a 100644 --- a/util/codebuild/codebuild-prowler-audit-account-cfn.yaml +++ b/util/codebuild/codebuild-prowler-audit-account-cfn.yaml @@ -179,6 +179,22 @@ Resources: - s3:GetBucketLocation Effect: Allow Resource: !Sub 'arn:aws:s3:::${ArtifactBucket}/*' + - PolicyName: ProwlerAdditions + PolicyDocument: + Version: '2012-10-17' + Statement: + - Action: + - s3:GetAccountPublicAccessBlock + - glue:GetConnections + - glue:SearchTables + - ds:ListAuthorizedApplications + - ec2:GetEbsEncryptionByDefault + - ecr:Describe* + - support:Describe* + - tag:GetTagKeys + - lambda:GetFunction + Effect: Allow + Resource: !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:catalog' - PolicyName: CodeBuild PolicyDocument: Version: '2012-10-17' diff --git a/util/org-multi-account/ProwlerEC2.yaml b/util/org-multi-account/ProwlerEC2.yaml index ad9390e4..94e56936 100644 --- a/util/org-multi-account/ProwlerEC2.yaml +++ b/util/org-multi-account/ProwlerEC2.yaml @@ -334,6 +334,7 @@ Resources: - s3:GetObject - s3:PutObject - s3:ListBucket + - s3:PutObjectAcl - PolicyName: Prowler-CrossAccount-AssumeRole PolicyDocument: Version: 2012-10-17 diff --git a/util/org-multi-account/ProwlerS3.yaml b/util/org-multi-account/ProwlerS3.yaml index 17b9f8b3..fc0ef4d9 100644 --- a/util/org-multi-account/ProwlerS3.yaml +++ b/util/org-multi-account/ProwlerS3.yaml @@ -60,6 +60,7 @@ Resources: - s3:GetObject - s3:PutObject - s3:ListBucket + - s3:PutObjectAcl Resource: - !Sub arn:${AWS::Partition}:s3:::${ProwlerS3} - !Sub arn:${AWS::Partition}:s3:::${ProwlerS3}/* diff --git a/util/org-multi-account/src/run-prowler-reports.sh b/util/org-multi-account/src/run-prowler-reports.sh index 54201b84..5de1e63b 100644 --- a/util/org-multi-account/src/run-prowler-reports.sh +++ b/util/org-multi-account/src/run-prowler-reports.sh @@ -91,9 +91,6 @@ for accountId in $ACCOUNTS_IN_ORGS; do # remove -g cislevel for a full report and add other formats if needed ./prowler/prowler -R "$ROLE" -A "$accountId" -g cislevel1 -M html echo "Report stored locally at: prowler/output/ directory" - # Upload Prowler Report to S3 - s3_account_session - aws s3 cp prowler/output/ "$S3/reports/" --recursive --include "*.html" TOTAL_SEC=$((SECONDS - START_TIME)) echo -e "Completed AWS Account: $accountId, using Role: $ROLE on $(date)" printf "Completed AWS Account: $accountId in %02dh:%02dm:%02ds" $((TOTAL_SEC / 3600)) $((TOTAL_SEC % 3600 / 60)) $((TOTAL_SEC % 60)) @@ -103,7 +100,16 @@ done # Wait for All Prowler Processes to finish wait -echo "Prowler Assessments Completed against All Accounts in the AWS Organization" +echo "Prowler Assessments Completed against All Accounts in the AWS Organization. Starting S3 copy operations..." + +# Upload Prowler Report to S3 +s3_account_session +aws s3 cp prowler/output/ "$S3/reports/" --recursive --include "*.html" --acl bucket-owner-full-control +echo "Assessment reports successfully copied to S3 bucket" + +# Final Wait for All Prowler Processes to finish +wait +echo "Prowler Assessments Completed" # Unset AWS Profile Variables unset_aws
Status Result Severity AccountIDCompliance Service CheckIDCheck TitleCheck OutputCheck TitleCheck Output CAF EpicRiskRemediationLink to docRiskRemediationDocsResource ID
INFO'$CHECK_SEVERITY''$ACCOUNT_NUM''$REPREGION''$CHECK_ASFF_COMPLIANCE_TYPE''$CHECK_SERVICENAME''$TITLE_ID''$TITLE_TEXT''$message''$CHECK_CAF_EPIC'

'$CHECK_RISK'

'$CHECK_REMEDIATION'

'$CHECK_DOC'
PASS'$CHECK_SEVERITY''$ACCOUNT_NUM''$REPREGION''$CHECK_ASFF_COMPLIANCE_TYPE''$CHECK_SERVICENAME''$TITLE_ID''$TITLE_TEXT''$message''$CHECK_CAF_EPIC'

'$CHECK_RISK'

'$CHECK_REMEDIATION'

'$CHECK_DOC'
FAIL'$CHECK_SEVERITY''$ACCOUNT_NUM''$REPREGION''$CHECK_ASFF_COMPLIANCE_TYPE''$CHECK_SERVICENAME''$TITLE_ID''$TITLE_TEXT''$message''$CHECK_CAF_EPIC'

'$CHECK_RISK'

'$CHECK_REMEDIATION'

'$CHECK_DOC'
WARN'$CHECK_SEVERITY''$ACCOUNT_NUM''$REPREGION''$CHECK_ASFF_COMPLIANCE_TYPE''$CHECK_SERVICENAME''$TITLE_ID''$TITLE_TEXT''$message''$CHECK_CAF_EPIC'

'$CHECK_RISK'

'$CHECK_REMEDIATION'

'$CHECK_DOC'
'$status''$CHECK_SEVERITY''$ACCOUNT_NUM''$REPREGION''$CHECK_ASFF_COMPLIANCE_TYPE''$CHECK_SERVICENAME''$TITLE_ID''$TITLE_TEXT''$message''$CHECK_CAF_EPIC'

'$CHECK_RISK'

'$CHECK_REMEDIATION'

'$CHECK_RESOURCE_ID'