mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
Compare commits
395 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24cccf64d6 | ||
|
|
77f07cccf8 | ||
|
|
40985212ab | ||
|
|
e461714226 | ||
|
|
11e5d44d9b | ||
|
|
a1d26b44c3 | ||
|
|
42af217524 | ||
|
|
4a1d4060ec | ||
|
|
0210c43b60 | ||
|
|
ca34590da0 | ||
|
|
44716cfab2 | ||
|
|
1f3aaa8c7b | ||
|
|
6213a7418c | ||
|
|
bf9ffc0485 | ||
|
|
fff605b356 | ||
|
|
e41e77ed78 | ||
|
|
a6516e4af8 | ||
|
|
4fe575030b | ||
|
|
178a34e40d | ||
|
|
5f3293af1e | ||
|
|
28a8ae7572 | ||
|
|
daa26ed14c | ||
|
|
9bd54ca30e | ||
|
|
d832b11047 | ||
|
|
f99d35888a | ||
|
|
4d683a7566 | ||
|
|
35fc8cd0bf | ||
|
|
447657140d | ||
|
|
5069fd29f9 | ||
|
|
b9a4f2c4e8 | ||
|
|
0d1807bd33 | ||
|
|
a77d3b0361 | ||
|
|
274d02576f | ||
|
|
5cebebba97 | ||
|
|
092dc84186 | ||
|
|
528e14d4cf | ||
|
|
9519539de3 | ||
|
|
1e1de4fa46 | ||
|
|
fe2d2b45bb | ||
|
|
74cbbddc5c | ||
|
|
e575fcd6b2 | ||
|
|
aca93b7526 | ||
|
|
029c330ed1 | ||
|
|
4ecc9c929c | ||
|
|
2abe36083f | ||
|
|
d473ebe3f2 | ||
|
|
a824e064b3 | ||
|
|
24780b4caa | ||
|
|
b35350291f | ||
|
|
f038074e0c | ||
|
|
f797805970 | ||
|
|
ef001af1ec | ||
|
|
2d712f6ab0 | ||
|
|
8b5733b5fe | ||
|
|
278e382f9a | ||
|
|
425fe16752 | ||
|
|
3452ecdf03 | ||
|
|
e65a11bc27 | ||
|
|
f2f82165ab | ||
|
|
f735de8836 | ||
|
|
9fc0f6c61c | ||
|
|
41ccd4517b | ||
|
|
2f17cfbc30 | ||
|
|
ab5968cbee | ||
|
|
5f8c2328f1 | ||
|
|
cc0b1bcf11 | ||
|
|
f006c81e6a | ||
|
|
9ed7d75c44 | ||
|
|
4c1d1887e4 | ||
|
|
cea0cfb47d | ||
|
|
754ff31ea3 | ||
|
|
49ec898b9e | ||
|
|
c2f541134b | ||
|
|
b3b903959b | ||
|
|
4806d5fc78 | ||
|
|
a755ec806a | ||
|
|
3c703de4f4 | ||
|
|
7d324bed65 | ||
|
|
b22b0af2ce | ||
|
|
4cc5cd1ab1 | ||
|
|
f3bfe90587 | ||
|
|
53ea126065 | ||
|
|
688f028698 | ||
|
|
74380a62d9 | ||
|
|
c84190c3d9 | ||
|
|
42f15ce164 | ||
|
|
23be47a9b6 | ||
|
|
ab75f19a62 | ||
|
|
20b127f516 | ||
|
|
cc5da42797 | ||
|
|
f979c7334f | ||
|
|
1087d60457 | ||
|
|
d2b3e5ecdc | ||
|
|
3db94a5a98 | ||
|
|
0d120a4536 | ||
|
|
0ab5d87b8f | ||
|
|
39c7ea52c6 | ||
|
|
933e4152cc | ||
|
|
fc3f4e830e | ||
|
|
7e803bb6a9 | ||
|
|
2d5d551696 | ||
|
|
8e1aa17a80 | ||
|
|
dd5bf6c7f8 | ||
|
|
7cb869ad33 | ||
|
|
3b264d556b | ||
|
|
e4a063f9d1 | ||
|
|
559b0585dc | ||
|
|
2da125ff8b | ||
|
|
53f097c2af | ||
|
|
b6e34adc24 | ||
|
|
7b5ece8007 | ||
|
|
fe65eaf373 | ||
|
|
4af3dc1254 | ||
|
|
923fadbfa9 | ||
|
|
3f68accf6f | ||
|
|
25d1aa9126 | ||
|
|
dce9d5c96d | ||
|
|
80c6900193 | ||
|
|
2e11e0a3f2 | ||
|
|
c630c02a26 | ||
|
|
e18cea213b | ||
|
|
8f91bfee24 | ||
|
|
a191a4eae6 | ||
|
|
ce7e07d66d | ||
|
|
ab5ed2c527 | ||
|
|
c513e7af6c | ||
|
|
2e1cead3a2 | ||
|
|
5c8b0aa942 | ||
|
|
15dda01842 | ||
|
|
d19ae27f7c | ||
|
|
b61af3a9eb | ||
|
|
687686c929 | ||
|
|
94a90599bd | ||
|
|
669469e618 | ||
|
|
73a5ee1bac | ||
|
|
0ff9806d70 | ||
|
|
961b79a4aa | ||
|
|
264b84ae2a | ||
|
|
031b68adde | ||
|
|
d737193b98 | ||
|
|
649192eb41 | ||
|
|
f83ce78e8f | ||
|
|
054043d78e | ||
|
|
603ed0b16f | ||
|
|
3a893889b6 | ||
|
|
2e181920ab | ||
|
|
4f4591dc42 | ||
|
|
18e5c0b8ae | ||
|
|
e748275fc5 | ||
|
|
4ca5b53948 | ||
|
|
8bb1529c2a | ||
|
|
61ef02ec50 | ||
|
|
fb45fa0c03 | ||
|
|
6a52ebe492 | ||
|
|
9b81fc0ac7 | ||
|
|
508a9354b7 | ||
|
|
63898690c8 | ||
|
|
d026ed5cac | ||
|
|
529fc6421d | ||
|
|
7aa1573275 | ||
|
|
bb69f51456 | ||
|
|
5cadd0c2f2 | ||
|
|
df5def48d9 | ||
|
|
5252518d97 | ||
|
|
231f0e6fb3 | ||
|
|
be0bc7aa65 | ||
|
|
c460e351a4 | ||
|
|
827b1fdb3b | ||
|
|
23a7c7f393 | ||
|
|
e683ea5384 | ||
|
|
2c531a2ffc | ||
|
|
e25ea9621b | ||
|
|
826cc00a7c | ||
|
|
65f787bfe0 | ||
|
|
77b3a9b4d9 | ||
|
|
f8db025fdf | ||
|
|
d4fad17416 | ||
|
|
ddb498320a | ||
|
|
31a4024dfc | ||
|
|
38c0b60141 | ||
|
|
81cc85a8fc | ||
|
|
ffcfef02a6 | ||
|
|
27305365ef | ||
|
|
08cd94fe5b | ||
|
|
40a2ea6c90 | ||
|
|
7e28f85247 | ||
|
|
64667ea9d0 | ||
|
|
70304dc2a2 | ||
|
|
e0a77b3e46 | ||
|
|
70de023114 | ||
|
|
b5ccdad3dc | ||
|
|
d0af7f439f | ||
|
|
64e38dd843 | ||
|
|
66c59ea1f7 | ||
|
|
fc77b4a55e | ||
|
|
4540fd77e6 | ||
|
|
d415ea6f20 | ||
|
|
ec8f51ba8a | ||
|
|
ad49d2accb | ||
|
|
67311e84d2 | ||
|
|
8f566ec690 | ||
|
|
75f6cbbdd6 | ||
|
|
4401d4209c | ||
|
|
44cfa71358 | ||
|
|
ecde62451c | ||
|
|
d5f22ab100 | ||
|
|
72b1421294 | ||
|
|
04acb7412b | ||
|
|
0327880258 | ||
|
|
6a9f32a284 | ||
|
|
3079bd51f3 | ||
|
|
dffb09b001 | ||
|
|
5e4eba54cc | ||
|
|
84d69ef5d8 | ||
|
|
cd52bf8b7d | ||
|
|
aba697aa99 | ||
|
|
18be522b87 | ||
|
|
49994d1c51 | ||
|
|
f3d617a1c8 | ||
|
|
de5b87c6ad | ||
|
|
f32b76987e | ||
|
|
1be58e02b2 | ||
|
|
8333c575ae | ||
|
|
02d2561d6b | ||
|
|
30b2f55ba1 | ||
|
|
253fa5ef54 | ||
|
|
188a681cb5 | ||
|
|
1fb8b47a9c | ||
|
|
2afdabf9bc | ||
|
|
3a989516d1 | ||
|
|
9e06297d5f | ||
|
|
1789dab4df | ||
|
|
eecb272f93 | ||
|
|
2ed3378556 | ||
|
|
bd9ae4bce7 | ||
|
|
459a688b7a | ||
|
|
30e2360acc | ||
|
|
d8c29cc263 | ||
|
|
7313628cc6 | ||
|
|
033e2623d3 | ||
|
|
2b95f69fa6 | ||
|
|
0ebdb1698f | ||
|
|
50d8359022 | ||
|
|
4bc64e938e | ||
|
|
8f852457ff | ||
|
|
5bd3f0b995 | ||
|
|
e5e5e84112 | ||
|
|
a430ad421b | ||
|
|
58fdd45424 | ||
|
|
85dc0408c2 | ||
|
|
c037067be2 | ||
|
|
4fa48671e0 | ||
|
|
a259571cb0 | ||
|
|
8b2c113614 | ||
|
|
e273ae3123 | ||
|
|
e04c34986e | ||
|
|
ea6d9c93fc | ||
|
|
cea45f43c8 | ||
|
|
d7d2246498 | ||
|
|
e6992e87ee | ||
|
|
c8622bc347 | ||
|
|
76e6657e42 | ||
|
|
de8336092b | ||
|
|
d50c3afebd | ||
|
|
f54bc4238e | ||
|
|
c7320ec7e2 | ||
|
|
a5ea0f59b2 | ||
|
|
3947ee2aae | ||
|
|
0db97d5a24 | ||
|
|
588976ac45 | ||
|
|
6eb68a1218 | ||
|
|
b1e7dc8519 | ||
|
|
c5f170307d | ||
|
|
e8b59b6722 | ||
|
|
ea886b84f2 | ||
|
|
89268e4875 | ||
|
|
8ee06449b7 | ||
|
|
a09055ff31 | ||
|
|
d640086112 | ||
|
|
5037cb03f2 | ||
|
|
085dd338f4 | ||
|
|
5a0366382b | ||
|
|
c4ddb8f14a | ||
|
|
df6c323a64 | ||
|
|
40117ed5dd | ||
|
|
2012bbb119 | ||
|
|
004f882a1d | ||
|
|
7bf636bfc7 | ||
|
|
b8c79154cb | ||
|
|
5cd7214f21 | ||
|
|
4f00760e88 | ||
|
|
660b573d05 | ||
|
|
1d45c45afa | ||
|
|
3693ee3692 | ||
|
|
c36a6067fa | ||
|
|
5325bab0ab | ||
|
|
e283d3587b | ||
|
|
b95cf5bc7b | ||
|
|
c6dfbfd0ec | ||
|
|
62991cfb48 | ||
|
|
8b4b59e9d5 | ||
|
|
303cdc7acd | ||
|
|
3275713aa8 | ||
|
|
08cdf3511f | ||
|
|
f28c4330b4 | ||
|
|
a6569a0a70 | ||
|
|
959bd8dfd4 | ||
|
|
a59aedc43b | ||
|
|
50b6e630d8 | ||
|
|
da25a02e80 | ||
|
|
967fe029c2 | ||
|
|
3582b424b0 | ||
|
|
65e2ff7951 | ||
|
|
ab66211f9b | ||
|
|
8e71c6e5c5 | ||
|
|
504a11bb2e | ||
|
|
f03eccf6c8 | ||
|
|
d0789859a3 | ||
|
|
1b4045d57c | ||
|
|
f406b4bbcf | ||
|
|
d9ced05d25 | ||
|
|
f5708d7db6 | ||
|
|
6dd0ab06d2 | ||
|
|
42220828ce | ||
|
|
4527522acb | ||
|
|
b4c4a46cc6 | ||
|
|
e0d86c134a | ||
|
|
7a44b8bcca | ||
|
|
a707b382b0 | ||
|
|
fff424dbfa | ||
|
|
2870f38bdc | ||
|
|
1956be4dc3 | ||
|
|
e4cf874c5c | ||
|
|
a2ccac97d9 | ||
|
|
917a323c15 | ||
|
|
ddad72fc5f | ||
|
|
b03aca80a1 | ||
|
|
9d526ff098 | ||
|
|
bde9482928 | ||
|
|
07f426aec0 | ||
|
|
3b2f5522fd | ||
|
|
ea89242644 | ||
|
|
da9cb41b3b | ||
|
|
bc9d4fe762 | ||
|
|
ec05e2f0f4 | ||
|
|
fa1a3b8406 | ||
|
|
a3d1ed5129 | ||
|
|
e284dd3afc | ||
|
|
c8cc343784 | ||
|
|
6d15bb67fe | ||
|
|
b60d320622 | ||
|
|
3290563716 | ||
|
|
4c0c6b181b | ||
|
|
10a99aa5ae | ||
|
|
7117399e14 | ||
|
|
6f678a1093 | ||
|
|
bc1271788c | ||
|
|
9d88a27e0a | ||
|
|
2bc3575de8 | ||
|
|
18e9e7f0e1 | ||
|
|
327323e32f | ||
|
|
3c2ad65246 | ||
|
|
069b54057b | ||
|
|
edf7826121 | ||
|
|
be4bbe4430 | ||
|
|
9bf3fd87ac | ||
|
|
11c7d55203 | ||
|
|
170557a422 | ||
|
|
5b0c6f8689 | ||
|
|
17f00f167f | ||
|
|
34b6c4446d | ||
|
|
6600df9be9 | ||
|
|
8f89a01541 | ||
|
|
b59d5db16b | ||
|
|
2e754a5370 | ||
|
|
2f9886efe2 | ||
|
|
71355b0c4c | ||
|
|
1203700d34 | ||
|
|
97a59cf5e4 | ||
|
|
8a3893cd33 | ||
|
|
1fc2b77bfb | ||
|
|
00e5e65176 | ||
|
|
8935233a05 | ||
|
|
c9c4620988 | ||
|
|
2700365101 | ||
|
|
bacdf6ed22 | ||
|
|
30cac002fa | ||
|
|
d818381bcf | ||
|
|
d78424b346 | ||
|
|
1727758479 | ||
|
|
9e0923407e | ||
|
|
79e02ce074 | ||
|
|
b4cb323de4 | ||
|
|
573fa46aac | ||
|
|
be29f2f0d9 |
1
.github/pull_request_template.md
vendored
Normal file
1
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
|
||||
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-rt-v][a-z]
|
||||
[._]ss[a-gi-z]
|
||||
[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
Session.vim
|
||||
Sessionx.vim
|
||||
|
||||
# Temporary
|
||||
.netrwhist
|
||||
*~
|
||||
# Auto-generated tag files
|
||||
tags
|
||||
# Persistent undo
|
||||
[._]*.un~
|
||||
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at community@prowler.cloud. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
14
Pipfile
Normal file
14
Pipfile
Normal file
@@ -0,0 +1,14 @@
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
boto3 = ">=1.9.188"
|
||||
ansi2html = ">=1.5.2"
|
||||
detect-secrets = ">=0.12.4"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
414
README.md
414
README.md
@@ -6,6 +6,7 @@
|
||||
- [Features](#features)
|
||||
- [Requirements and Installation](#requirements-and-installation)
|
||||
- [Usage](#usage)
|
||||
- [Advanced Usage](#advanced-usage)
|
||||
- [Fix](#fix)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
@@ -39,7 +40,7 @@ It covers hardening and security best practices for all AWS regions related to t
|
||||
- Extras (39 checks) *see Extras section* [extras]
|
||||
- Forensics related group of checks [forensics-ready]
|
||||
- GDPR [gdpr] Read more [here](#gdpr-checks)
|
||||
- HIPPA [hippa] Read more [here](#hipaa-checks)
|
||||
- HIPAA [hipaa] Read more [here](#hipaa-checks)
|
||||
|
||||
|
||||
For a comprehensive list and resolution look at the guide on the link above.
|
||||
@@ -55,34 +56,45 @@ With Prowler you can:
|
||||
|
||||
This script has been written in bash using AWS-CLI and it works in Linux and OSX.
|
||||
|
||||
- Make sure your AWS-CLI is installed on your workstation, with Python pip already installed:
|
||||
- Make sure the latest version of AWS-CLI is installed on your workstation, and other components needed, with Python pip already installed:
|
||||
|
||||
```sh
|
||||
pip install awscli
|
||||
pip install awscli ansi2html detect-secrets
|
||||
```
|
||||
|
||||
Or install it using "brew", "apt", "yum" or manually from <https://aws.amazon.com/cli/>
|
||||
AWS-CLI can be also installed it using "brew", "apt", "yum" or manually from <https://aws.amazon.com/cli/>, but `ansi2html` and `detect-secrets` has to be installed using `pip`. You will need to install `jq` to get more accuracy in some checks.
|
||||
|
||||
- Make sure jq is installed (example below with "apt" but use a valid package manager for your OS):
|
||||
```sh
|
||||
sudo apt install jq
|
||||
```
|
||||
|
||||
- Previous steps, from your workstation:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Alfresco/prowler
|
||||
git clone https://github.com/toniblyx/prowler
|
||||
cd prowler
|
||||
```
|
||||
|
||||
- Make sure you have properly configured your AWS-CLI with a valid Access Key and Region:
|
||||
- Make sure you have properly configured your AWS-CLI with a valid Access Key and Region or declare AWS variables properly (or intance profile):
|
||||
|
||||
```sh
|
||||
aws configure
|
||||
```
|
||||
or
|
||||
```sh
|
||||
export AWS_ACCESS_KEY_ID="ASXXXXXXX"
|
||||
export AWS_SECRET_ACCESS_KEY="XXXXXXXXX"
|
||||
export AWS_SESSION_TOKEN="XXXXXXXXX"
|
||||
```
|
||||
|
||||
- Make sure your Secret and Access Keys are associated to a user with proper permissions to do all checks. To make sure add SecurityAuditor default policy to your user. Policy ARN is
|
||||
- Those credentials must be associated to a user or role with proper permissions to do all checks. To make sure add SecurityAuditor default policy to your user. Policy ARN is
|
||||
|
||||
```sh
|
||||
arn:aws:iam::aws:policy/SecurityAudit
|
||||
```
|
||||
|
||||
> In some cases you may need more list or get permissions in some services, look at the Troubleshooting section for a more comprehensive policy if you find issues with the default SecurityAudit policy.
|
||||
> Additional permissions needed: to make sure Prowler can scan all services included in the group *Extras*, make sure you attach also the custom policy [prowler-additions-policy.json](https://github.com/toniblyx/prowler/blob/master/iam/prowler-additions-policy.json) to the role you are using.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -94,6 +106,12 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
|
||||
Use `-l` to list all available checks and group of checks (sections)
|
||||
|
||||
If you want to avoid installing dependences run it using Docker:
|
||||
|
||||
```sh
|
||||
docker run -ti --rm --name prowler --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN toniblyx/prowler:latest
|
||||
```
|
||||
|
||||
1. For custom AWS-CLI profile and region, use the following: (it will use your custom profile and run checks over all regions when needed):
|
||||
|
||||
```sh
|
||||
@@ -105,6 +123,19 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
```sh
|
||||
./prowler -c check310
|
||||
```
|
||||
With Docker:
|
||||
```sh
|
||||
docker run -ti --rm --name prowler --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN toniblyx/prowler:latest "-c check310"
|
||||
```
|
||||
|
||||
or multiple checks separated by comma:
|
||||
```sh
|
||||
./prowler -c check310,check722
|
||||
```
|
||||
or all checks but some of them:
|
||||
```sh
|
||||
./prowler -E check42,check43
|
||||
```
|
||||
|
||||
or for custom profile and region:
|
||||
|
||||
@@ -117,6 +148,10 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
```sh
|
||||
./prowler -g group1 # for iam related checks
|
||||
```
|
||||
or exclude some checks in the group:
|
||||
```sh
|
||||
./prowler -g group4 -E check42,check43
|
||||
```
|
||||
|
||||
Valid check numbers are based on the AWS CIS Benchmark guide, so 1.1 is check11 and 3.10 is check310
|
||||
|
||||
@@ -150,10 +185,10 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
./prowler -M mono | aws s3 cp - s3://bucket-name/prowler-report.txt
|
||||
```
|
||||
|
||||
1. To perform an assessment based on CIS Profile Definitions you can use level1 or level2 with `-c` flag, more information about this [here, page 8](https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf):
|
||||
1. To perform an assessment based on CIS Profile Definitions you can use cislevel1 or cislevel2 with `-g` flag, more information about this [here, page 8](https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf):
|
||||
|
||||
```sh
|
||||
./prowler -c level1
|
||||
./prowler -g cislevel1
|
||||
```
|
||||
|
||||
1. If you want to run Prowler to check multiple AWS accounts in parallel (runs up to 4 simultaneously `-P 4`):
|
||||
@@ -178,7 +213,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
-c <check_id> specify a check id, to see all available checks use -l option
|
||||
(i.e.: check11 for check 1.1 or extra71 for extra check 71)
|
||||
-g <group_id> specify a group of checks by id, to see all available group of checks use -L
|
||||
(i.e.: check3 for entire section 3, level1 for CIS Level 1 Profile Definitions or forensics-ready)
|
||||
(i.e.: check3 for entire section 3, cislevel1 for CIS Level 1 Profile Definitions or forensics-ready)
|
||||
-f <filterregion> specify an AWS region to run checks against
|
||||
(i.e.: us-west-1)
|
||||
-m <maxitems> specify the maximum number of items to return for long-running requests (default: 100)
|
||||
@@ -189,10 +224,54 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
|
||||
-l list all available checks only (does not perform any check)
|
||||
-L list all groups (does not perform any check)
|
||||
-e exclude group extras
|
||||
-E execute all tests except a list of specified checks separated by comma (i.e. check21,check31)
|
||||
-b do not print Prowler banner
|
||||
-V show version number & exit
|
||||
-s show scoring report
|
||||
-x specify external directory with custom checks (i.e. /my/own/checks, files must start by check)
|
||||
-q suppress info messages and passing test output
|
||||
-A account id for the account where to assume a role, requires -R and -T
|
||||
(i.e.: 123456789012)
|
||||
-R role name to assume in the account, requires -A and -T
|
||||
(i.e.: ProwlerRole)
|
||||
-T session durantion given to that role credentials in seconds, default 1h (3600) recommended 12h, requires -R and -T
|
||||
(i.e.: 43200)
|
||||
-h this help
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Assume Role:
|
||||
|
||||
Prowler uses the AWS CLI underneath so it uses the same authentication methods. However, there are few ways to run Prowler against multiple accounts using IAM Assume Role feature depending on eachg use case. You can just set up your custom profile inside `~/.aws/config` with all needed information about the role to assume then call it with `./prowler -p your-custom-profile`. Additionally you can use `-A 123456789012` and `-R RemoteRoleToAssume` and Prowler will get those temporary credentials using `aws sts assume-role`, set them up as environment variables and run against that given account.
|
||||
|
||||
```
|
||||
./prowler -A 123456789012 -R ProwlerRole
|
||||
```
|
||||
|
||||
> *NOTE 1 about Session Duration*: By default it gets credentials valid for 1 hour (3600 seconds). Depending on the mount of checks you run and the size of your infrastructure, Prowler may require more than 1 hour to finish. Use option `-T <seconds>` to allow up to 12h (43200 seconds). To allow more than 1h you need to modify *"Maximum CLI/API session duration"* for that particular role, read more [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session).
|
||||
|
||||
> *NOTE 2 about Session Duration*: Bear in mind that if you are using roles assumed by role chaining there is a hard limit of 1 hour so consider not using role chaining if possible, read more about that, in foot note 1 below the table [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html).
|
||||
|
||||
For example, if you want to get only the fails in CSV format from all checks regarding RDS without banner from the AWS Account 123456789012 assuming the role RemoteRoleToAssume and set a fixed session duration of 1h:
|
||||
|
||||
```
|
||||
./prowler -A 123456789012 -R RemoteRoleToAssume -T 3600 -b -M cvs -q -g rds
|
||||
```
|
||||
|
||||
### Custom folder for custom checks
|
||||
|
||||
Flag `-x /my/own/checks` will include any check in that particular directory. To see how to write checks see [Add Custom Checks](#add-custom-checks) section.
|
||||
|
||||
### Show or log only FAILs
|
||||
|
||||
In order to remove noise and get only FAIL findings there is a `-q` flag that makes Prowler to show and log only FAILs. It can be combined with any other option.
|
||||
|
||||
```
|
||||
./prowler -q -M csv -b
|
||||
```
|
||||
|
||||
|
||||
## How to fix every FAIL
|
||||
|
||||
Check your report and fix the issues following all specific guidelines per check in <https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf>
|
||||
@@ -217,217 +296,66 @@ If you are using an STS token for AWS-CLI and your session is expired you probab
|
||||
A client error (ExpiredToken) occurred when calling the GenerateCredentialReport operation: The security token included in the request is expired
|
||||
```
|
||||
|
||||
To fix it, please renew your token by authenticating again to the AWS API.
|
||||
To fix it, please renew your token by authenticating again to the AWS API, see next section below if you use MFA.
|
||||
|
||||
### Run Prowler with MFA protected credentials
|
||||
|
||||
To run Prowler using a profile that requires MFA you just need to get the session token before hand. Just make sure you use this command:
|
||||
|
||||
```
|
||||
aws --profile <YOUR_AWS_PROFILE> sts get-session-token --duration 129600 --serial-number <ARN_OF_MFA> --token-code <MFA_TOKEN_CODE> --output text
|
||||
```
|
||||
Once you get your token you can export it as environment variable:
|
||||
```
|
||||
export AWS_PROFILE=YOUR_AWS_PROFILE
|
||||
export AWS_SESSION_TOKEN=YOUR_NEW_TOKEN
|
||||
AWS_SECRET_ACCESS_KEY=YOUR_SECRET
|
||||
export AWS_ACCESS_KEY_ID=YOUR_KEY
|
||||
```
|
||||
or set manually up your `~/.aws/credentials` file properly.
|
||||
|
||||
There are some helpfull tools to save time in this process like [aws-mfa-script](https://github.com/asagage/aws-mfa-script) or [aws-cli-mfa](https://github.com/sweharris/aws-cli-mfa).
|
||||
|
||||
### Custom IAM Policy
|
||||
|
||||
Instead of using default policy SecurityAudit for the account you use for checks you may need to create a custom policy with a few more permissions (get and list, not change!) here you go a good example for a "ProwlerPolicyReadOnly":
|
||||
Some new and specific checks require Prowler to inherit more permissions than SecurityAudit to work properly. In addition to the AWS managed policy "SecurityAudit" for the role you use for checks you may need to create a custom policy with a few more permissions (get and list and additional services mostly). Here you go a good example for a "ProwlerReadOnlyPolicy" (see below bootstrap script for set it up):
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Action": [
|
||||
"acm:describecertificate",
|
||||
"acm:listcertificates",
|
||||
"apigateway:get",
|
||||
"autoscaling:describe*",
|
||||
"cloudformation:describestack*",
|
||||
"cloudformation:getstackpolicy",
|
||||
"cloudformation:gettemplate",
|
||||
"cloudformation:liststack*",
|
||||
"cloudfront:get*",
|
||||
"cloudfront:list*",
|
||||
"cloudtrail:describetrails",
|
||||
"cloudtrail:geteventselectors",
|
||||
"cloudtrail:gettrailstatus",
|
||||
"cloudtrail:listtags",
|
||||
"cloudwatch:describe*",
|
||||
"codecommit:batchgetrepositories",
|
||||
"codecommit:getbranch",
|
||||
"codecommit:getobjectidentifier",
|
||||
"codecommit:getrepository",
|
||||
"codecommit:list*",
|
||||
"codedeploy:batch*",
|
||||
"codedeploy:get*",
|
||||
"codedeploy:list*",
|
||||
"config:deliver*",
|
||||
"config:describe*",
|
||||
"config:get*",
|
||||
"datapipeline:describeobjects",
|
||||
"datapipeline:describepipelines",
|
||||
"datapipeline:evaluateexpression",
|
||||
"datapipeline:getpipelinedefinition",
|
||||
"datapipeline:listpipelines",
|
||||
"datapipeline:queryobjects",
|
||||
"datapipeline:validatepipelinedefinition",
|
||||
"directconnect:describe*",
|
||||
"dynamodb:listtables",
|
||||
"ec2:describe*",
|
||||
"ecr:describe*",
|
||||
"ecs:describe*",
|
||||
"ecs:list*",
|
||||
"elasticache:describe*",
|
||||
"elasticbeanstalk:describe*",
|
||||
"elasticloadbalancing:describe*",
|
||||
"elasticmapreduce:describejobflows",
|
||||
"elasticmapreduce:listclusters",
|
||||
"es:describeelasticsearchdomainconfig",
|
||||
"es:listdomainnames",
|
||||
"firehose:describe*",
|
||||
"firehose:list*",
|
||||
"glacier:listvaults",
|
||||
"guardduty:listdetectors",
|
||||
"iam:generatecredentialreport",
|
||||
"iam:get*",
|
||||
"iam:list*",
|
||||
"kms:describe*",
|
||||
"kms:get*",
|
||||
"kms:list*",
|
||||
"lambda:getpolicy",
|
||||
"lambda:listfunctions",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:DescribeMetricFilters",
|
||||
"rds:describe*",
|
||||
"rds:downloaddblogfileportion",
|
||||
"rds:listtagsforresource",
|
||||
"redshift:describe*",
|
||||
"route53:getchange",
|
||||
"route53:getcheckeripranges",
|
||||
"route53:getgeolocation",
|
||||
"route53:gethealthcheck",
|
||||
"route53:gethealthcheckcount",
|
||||
"route53:gethealthchecklastfailurereason",
|
||||
"route53:gethostedzone",
|
||||
"route53:gethostedzonecount",
|
||||
"route53:getreusabledelegationset",
|
||||
"route53:listgeolocations",
|
||||
"route53:listhealthchecks",
|
||||
"route53:listhostedzones",
|
||||
"route53:listhostedzonesbyname",
|
||||
"route53:listqueryloggingconfigs",
|
||||
"route53:listresourcerecordsets",
|
||||
"route53:listreusabledelegationsets",
|
||||
"route53:listtagsforresource",
|
||||
"route53:listtagsforresources",
|
||||
"route53domains:getdomaindetail",
|
||||
"route53domains:getoperationdetail",
|
||||
"route53domains:listdomains",
|
||||
"route53domains:listoperations",
|
||||
"route53domains:listtagsfordomain",
|
||||
"s3:getbucket*",
|
||||
"s3:getlifecycleconfiguration",
|
||||
"s3:getobjectacl",
|
||||
"s3:getobjectversionacl",
|
||||
"s3:listallmybuckets",
|
||||
"sdb:domainmetadata",
|
||||
"sdb:listdomains",
|
||||
"ses:getidentitydkimattributes",
|
||||
"ses:getidentityverificationattributes",
|
||||
"ses:listidentities",
|
||||
"ses:listverifiedemailaddresses",
|
||||
"ses:sendemail",
|
||||
"sns:gettopicattributes",
|
||||
"sns:listsubscriptionsbytopic",
|
||||
"sns:listtopics",
|
||||
"sqs:getqueueattributes",
|
||||
"sqs:listqueues",
|
||||
"support:describetrustedadvisorchecks",
|
||||
"tag:getresources",
|
||||
"tag:gettagkeys"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}]
|
||||
}
|
||||
```
|
||||
[iam/prowler-additions-policy.json](iam/prowler-additions-policy.json)
|
||||
|
||||
### Incremental IAM Policy
|
||||
|
||||
Alternatively, here is a policy which defines the permissions which are NOT present in the AWS Managed SecurityAudit policy. Attach both this policy and the [AWS Managed SecurityAudit policy](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/SecurityAudit$jsonEditor) to the group and you're good to go.
|
||||
|
||||
```sh
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"support:DescribeTrustedAdvisorChecks"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
> Note: Action `ec2:get*` is included in "ProwlerReadOnlyPolicy" policy above, that includes `get-password-data`, type `aws ec2 get-password-data help` to better understand its implications.
|
||||
|
||||
### Bootstrap Script
|
||||
|
||||
Quick bash script to set up a "prowler" IAM user and "SecurityAudit" group with the required permissions. To run the script below, you need user with administrative permissions; set the `AWS_DEFAULT_PROFILE` to use that account.
|
||||
Quick bash script to set up a "prowler" IAM user with "SecurityAudit" group with the required permissions (including "ProwlerReadOnlyPolicy"). To run the script below, you need user with administrative permissions; set the `AWS_DEFAULT_PROFILE` to use that account:
|
||||
|
||||
```sh
|
||||
export AWS_DEFAULT_PROFILE=default
|
||||
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' | tr -d '"')
|
||||
aws iam create-group --group-name SecurityAudit
|
||||
aws iam create-policy --policy-name ProwlerAuditAdditions --policy-document file://$(pwd)/iam/prowler-policy-additions.json
|
||||
aws iam create-policy --policy-name ProwlerReadOnlyPolicy --policy-document file://$(pwd)/iam/prowler-additions-policy.json
|
||||
aws iam attach-group-policy --group-name SecurityAudit --policy-arn arn:aws:iam::aws:policy/SecurityAudit
|
||||
aws iam attach-group-policy --group-name SecurityAudit --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/ProwlerAuditAdditions
|
||||
aws iam attach-group-policy --group-name SecurityAudit --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/ProwlerReadOnlyPolicy
|
||||
aws iam create-user --user-name prowler
|
||||
aws iam add-user-to-group --user-name prowler --group-name SecurityAudit
|
||||
aws iam create-access-key --user-name prowler
|
||||
unset ACCOUNT_ID AWS_DEFAULT_PROFILE
|
||||
```
|
||||
|
||||
The `aws iam create-access-key` command will output the secret access key and the key id; keep these somewhere safe, and add them to `~/.aws/credentials` with an appropriate profile name to use them with prowler. This is the only time they secret key will be shown. If you loose it, you will need to generate a replacement.
|
||||
The `aws iam create-access-key` command will output the secret access key and the key id; keep these somewhere safe, and add them to `~/.aws/credentials` with an appropriate profile name to use them with prowler. This is the only time they secret key will be shown. If you lose it, you will need to generate a replacement.
|
||||
|
||||
## Extras
|
||||
|
||||
We are adding additional checks to improve the information gather from each account, these checks are out of the scope of the CIS benchmark for AWS but we consider them very helpful to get to know each AWS account set up and find issues on it.
|
||||
|
||||
Note: Some of these checks for publicly facing resources may not actually be fully public due to other layered controls like S3 Bucket Policies, Security Groups or Network ACLs.
|
||||
Some of these checks look for publicly facing resources may not actually be fully public due to other layered controls like S3 Bucket Policies, Security Groups or Network ACLs.
|
||||
|
||||
At this moment we have 37 extra checks:
|
||||
To list all existing checks please run the command below:
|
||||
|
||||
- 7.1 (`extra71`) Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.2 (`extra72`) Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.3 (`extra73`) Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.4 (`extra74`) Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.5 (`extra75`) Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.6 (`extra76`) Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.7 (`extra77`) Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.8 (`extra78`) Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.9 (`extra79`) Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.10 (`extra710`) Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.11 (`extra711`) Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.12 (`extra712`) Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.13 (`extra713`) Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.14 (`extra714`) Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.15 (`extra715`) Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.16 (`extra716`) Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.17 (`extra717`) Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.18 (`extra718`) Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.19 (`extra719`) Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.20 (`extra720`) Check if Lambda functions are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.21 (`extra721`) Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.22 (`extra722`) Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.23 (`extra723`) Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.24 (`extra724`) Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.25 (`extra725`) Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.26 (`extra726`) Check Trusted Advisor for errors and warnings (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.27 (`extra727`) Check if SQS queues have policy set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.28 (`extra728`) Check if SQS queues have Server Side Encryption enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.29 (`extra729`) Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.30 (`extra730`) Check if ACM Certificates are about to expire in 7 days or less (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.31 (`extra731`) Check if SNS topics have policy set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.32 (`extra732`) Check if Geo restrictions are enabled in CloudFront distributions (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.33 (`extra733`) Check if there are SAML Providers then STS can be used (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.34 (`extra734`) Check if S3 buckets have default encryption (SSE) enabled and policy to enforce it (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.35 (`extra735`) Check if RDS instances storage is encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.36 (`extra736`) Check exposed KMS keys (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.37 (`extra737`) Check KMS keys with key rotation disabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.38 (`extra738`) Check if CloudFront distributions are set to HTTPS (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.38 (`extra739`) Check if ELBs have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.40 (`extra740`) Check if EBS snapshots are encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
```
|
||||
./prowler -l
|
||||
```
|
||||
|
||||
>There are some checks not included in that list, they are experimental or checks that takes long to run like `extra759` and `extra760` (search for secrets in Lambda function variables and code).
|
||||
|
||||
To check all extras in one command:
|
||||
|
||||
@@ -443,30 +371,9 @@ or to run just one of the checks:
|
||||
|
||||
## Forensics Ready Checks
|
||||
|
||||
With this group of checks, Prowler looks if each service with logging or audit capabilities has them enabled to ensure all needed evidences are recorded and collected for an eventual digital forensic investigation in case of incident. List of checks part of this group (you can also see all groups with `./prowler -l`):
|
||||
With this group of checks, Prowler looks if each service with logging or audit capabilities has them enabled to ensure all needed evidences are recorded and collected for an eventual digital forensic investigation in case of incident. List of checks part of this group (you can also see all groups with `./prowler -L`). The list of checks can be seen in the group file at:
|
||||
|
||||
- 2.1 Ensure CloudTrail is enabled in all regions (Scored)
|
||||
- 2.2 Ensure CloudTrail log file validation is enabled (Scored)
|
||||
- 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)
|
||||
- 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)
|
||||
- 2.5 Ensure AWS Config is enabled in all regions (Scored)
|
||||
- 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)
|
||||
- 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)
|
||||
- 4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored)
|
||||
- 7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.20 Check if Lambda functions are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.24 Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.25 Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.38 Check if ELBs have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
[groups/group8_forensics](groups/group8_forensics)
|
||||
|
||||
The `forensics-ready` group of checks uses existing and extra checks. To get a forensics readiness report, run this command:
|
||||
|
||||
@@ -476,44 +383,9 @@ The `forensics-ready` group of checks uses existing and extra checks. To get a f
|
||||
|
||||
## GDPR Checks
|
||||
|
||||
With this group of checks, Prowler shows result of checks related to GDPR, more information [here](https://github.com/toniblyx/prowler/issues/189). The list of checks showed by this group is as follows:
|
||||
With this group of checks, Prowler shows result of checks related to GDPR, more information [here](https://github.com/toniblyx/prowler/issues/189). The list of checks can be seen in the group file at:
|
||||
|
||||
- 7.18 [extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.25 [extra725] Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.27 [extra727] Check if SQS queues have policy set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 1.2 [check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)
|
||||
- 1.13 [check113] Ensure MFA is enabled for the root account (Scored)
|
||||
- 1.14 [check114] Ensure hardware MFA is enabled for the root account (Scored)
|
||||
- 7.1 [extra71] Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.31 [extra731] Check if SNS topics have policy set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.32 [extra732] Check if Geo restrictions are enabled in CloudFront distributions (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.33 [extra733] Check if there are SAML Providers then STS can be used (Not Scored) (Not part of CIS benchmark)
|
||||
- 2.5 [check25] Ensure AWS Config is enabled in all regions (Scored)
|
||||
- 3.9 [check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)
|
||||
- 2.1 [check21] Ensure CloudTrail is enabled in all regions (Scored)
|
||||
- 2.2 [check22] Ensure CloudTrail log file validation is enabled (Scored)
|
||||
- 2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)
|
||||
- 2.4 [check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)
|
||||
- 2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)
|
||||
- 2.7 [check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)
|
||||
- 3.5 [check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)
|
||||
- 7.26 [extra726] Check Trusted Advisor for errors and warnings (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.14 [extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.15 [extra715] Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.17 [extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.19 [extra719] Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.20 [extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.21 [extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.22 [extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 4.3 [check43] Ensure the default security group of every VPC restricts all traffic (Scored)
|
||||
- 2.5 [check25] Ensure AWS Config is enabled in all regions (Scored)
|
||||
- 7.14 [extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.29 [extra729] Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.34 [extra734] Check if S3 buckets have default encryption (SSE) enabled and policy to enforce it (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.35 [extra735] Check if RDS instances storage is encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.36 [extra736] Check exposed KMS keys (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.38 [extra738] Check if CloudFront distributions are set to HTTPS (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.40 [extra740] Check if EBS snapshots are encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
[groups/group9_gdpr](groups/group9_gdpr)
|
||||
|
||||
The `gdpr` group of checks uses existing and extra checks. To get a GDPR report, run this command:
|
||||
|
||||
@@ -523,24 +395,18 @@ The `gdpr` group of checks uses existing and extra checks. To get a GDPR report,
|
||||
|
||||
## HIPAA Checks
|
||||
|
||||
With this group of checks, Prowler shows result of checks related to HIPAA, more information [here](https://github.com/toniblyx/prowler/issues/227). The list of checks showed by this group is as follows:
|
||||
With this group of checks, Prowler shows results of controls related to the "Security Rule" of the Health Insurance Portability and Accountability Act aka [HIPAA](https://www.hhs.gov/hipaa/for-professionals/security/index.html) as defined in [45 CFR Subpart C - Security Standards for the Protection of Electronic Protected Health Information](https://www.law.cornell.edu/cfr/text/45/part-164/subpart-C) within [PART 160 - GENERAL ADMINISTRATIVE REQUIREMENTS](https://www.law.cornell.edu/cfr/text/45/part-160) and [Subpart A](https://www.law.cornell.edu/cfr/text/45/part-164/subpart-A) and [Subpart C](https://www.law.cornell.edu/cfr/text/45/part-164/subpart-C) of PART 164 - SECURITY AND PRIVACY
|
||||
|
||||
- 1.13 [check113] Ensure MFA is enabled for the root account (Scored)
|
||||
- 2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)
|
||||
- 2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)
|
||||
- 2.7 [check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)
|
||||
- 2.9 [check29] Ensure VPC Flow Logging is Enabled in all VPCs (Scored)
|
||||
- 7.18 [extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.25 [extra725] Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.2 [extra72] Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.5 [extra75] Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.39 [extra739] Check if ELBs have logging enabled (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.29 [extra729] Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.34 [extra734] Check if S3 buckets have default encryption (SSE) enabled and policy to enforce it (Not Scored) (Not part of CIS benchmark)
|
||||
- 3.8 [check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)
|
||||
- 7.3 [extra73] Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.40 [extra740] Check if EBS snapshots are encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
- 7.35 [extra735] Check if RDS instances storage is encrypted (Not Scored) (Not part of CIS benchmark)
|
||||
More information on the original PR is [here](https://github.com/toniblyx/prowler/issues/227).
|
||||
|
||||
### Note on Business Associate Addendum's (BAA)
|
||||
Under the HIPAA regulations, cloud service providers (CSPs) such as AWS are considered business associates. The Business Associate Addendum (BAA) is an AWS contract that is required under HIPAA rules to ensure that AWS appropriately safeguards protected health information (PHI). The BAA also serves to clarify and limit, as appropriate, the permissible uses and disclosures of PHI by AWS, based on the relationship between AWS and our customers, and the activities or services being performed by AWS. Customers may use any AWS service in an account designated as a HIPAA account, but they should only process, store, and transmit protected health information (PHI) in the HIPAA-eligible services defined in the Business Associate Addendum (BAA). For the latest list of HIPAA-eligible AWS services, see [HIPAA Eligible Services Reference](https://aws.amazon.com/compliance/hipaa-eligible-services-reference/).
|
||||
|
||||
More information on AWS & HIPAA can be found [here](https://aws.amazon.com/compliance/hipaa-compliance/)
|
||||
|
||||
The list of checks showed by this group is as follows, they will be mostly relevant for Subsections [164.306 Security standards: General rules](https://www.law.cornell.edu/cfr/text/45/164.306) and [164.312 Technical safeguards](https://www.law.cornell.edu/cfr/text/45/164.312). Prowler is only able to make checks in the spirit of the technical requirements outlined in these Subsections, and cannot cover all procedural controls required. They be found in the group file at:
|
||||
|
||||
[groups/group10_hipaa](groups/group10_hipaa)
|
||||
|
||||
The `hipaa` group of checks uses existing and extra checks. To get a HIPAA report, run this command:
|
||||
|
||||
@@ -568,6 +434,10 @@ In order to add any new check feel free to create a new extra check in the extra
|
||||
|
||||
## Third Party Integrations
|
||||
|
||||
### AWS Security Hub
|
||||
|
||||
There is a blog post about that integration in the AWS Security blog here <https://aws.amazon.com/blogs/security/use-aws-fargate-prowler-send-security-configuration-findings-about-aws-services-security-hub/>
|
||||
|
||||
### Telegram
|
||||
|
||||
Javier Pecete has done an awesome job integrating Prowler with Telegram, you have more details here <https://github.com/i4specete/ServerTelegramBot>
|
||||
|
||||
@@ -16,6 +16,22 @@ CHECK_ALTERNATE_check101="check11"
|
||||
|
||||
check11(){
|
||||
# "Avoid the use of the root account (Scored)."
|
||||
COMMAND11=$(cat $TEMP_REPORT_FILE| grep '<root_account>' | cut -d, -f5,11,16 | sed 's/,/\ /g')
|
||||
textInfo "Root account last accessed (password key_1 key_2): $COMMAND11"
|
||||
MAX_DAYS=-1
|
||||
last_login_dates=$(cat $TEMP_REPORT_FILE | awk -F, '{ print $1,$5,$11,$16 }' | grep '<root_account>' | cut -d' ' -f2,3,4)
|
||||
|
||||
failures=0
|
||||
for date in $last_login_dates; do
|
||||
if [[ ${date%T*} =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]];then
|
||||
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"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $failures == 0 ]]; then
|
||||
textPass "Root user in the account wasn't accessed in the last ${MAX_DAYS#-} days"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ CHECK_ALTERNATE_check111="check111"
|
||||
check111(){
|
||||
# "Ensure IAM password policy expires passwords within 90 days or less (Scored)"
|
||||
COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query PasswordPolicy.MaxPasswordAge --output text 2> /dev/null)
|
||||
if [[ $COMMAND111 ]];then
|
||||
if [[ $COMMAND111 == [0-9]* ]];then
|
||||
if [[ "$COMMAND111" -le "90" ]];then
|
||||
textPass "Password Policy includes expiration (Value: $COMMAND111)"
|
||||
else
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
CHECK_ID_check117="1.17"
|
||||
CHECK_TITLE_check117="[check117] Maintain current contact details (Scored)"
|
||||
CHECK_SCORED_check117="SCORED"
|
||||
CHECK_TITLE_check117="[check117] Maintain current contact details (Not Scored)"
|
||||
CHECK_SCORED_check117="NOT_SCORED"
|
||||
CHECK_TYPE_check117="LEVEL1"
|
||||
CHECK_ALTERNATE_check117="check117"
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
CHECK_ID_check118="1.18"
|
||||
CHECK_TITLE_check118="[check118] Ensure security contact information is registered (Scored)"
|
||||
CHECK_SCORED_check118="SCORED"
|
||||
CHECK_TITLE_check118="[check118] Ensure security contact information is registered (Not Scored)"
|
||||
CHECK_SCORED_check118="NOT_SCORED"
|
||||
CHECK_TYPE_check118="LEVEL1"
|
||||
CHECK_ALTERNATE_check118="check118"
|
||||
|
||||
|
||||
@@ -15,7 +15,21 @@ CHECK_TYPE_check119="LEVEL2"
|
||||
CHECK_ALTERNATE_check119="check119"
|
||||
|
||||
check119(){
|
||||
# "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)"
|
||||
textInfo "No command available for check 1.19 "
|
||||
textInfo "See section 1.19 on the CIS Benchmark guide for details "
|
||||
for regx in $REGIONS; do
|
||||
EC2_DATA=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[].Instances[].[InstanceId, IamInstanceProfile.Arn]')
|
||||
EC2_DATA=$(echo $EC2_DATA | jq '.[]|{InstanceId: .[0], ProfileArn: .[1]}')
|
||||
INSTANCE_LIST=$(echo $EC2_DATA | jq -r '.InstanceId')
|
||||
if [[ $INSTANCE_LIST ]]; then
|
||||
for instance in $INSTANCE_LIST; do
|
||||
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
|
||||
else
|
||||
textPass "$regx: Instance $instance associated with role ${PROFILEARN##*/}." $regx
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No EC2 instances found" $regx
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -19,15 +19,16 @@ check120(){
|
||||
SUPPORTPOLICYARN=$($AWSCLI iam list-policies --query "Policies[?PolicyName == 'AWSSupportAccess'].Arn" $PROFILE_OPT --region $REGION --output text)
|
||||
if [[ $SUPPORTPOLICYARN ]];then
|
||||
for policyarn in $SUPPORTPOLICYARN;do
|
||||
POLICYUSERS=$($AWSCLI iam list-entities-for-policy --policy-arn $SUPPORTPOLICYARN $PROFILE_OPT --region $REGION --output json)
|
||||
if [[ $POLICYUSERS ]];then
|
||||
textPass "Support Policy attached to $policyarn"
|
||||
for user in $(echo "$POLICYUSERS" | grep UserName | cut -d'"' -f4) ; do
|
||||
textInfo "User $user has support access via $policyarn"
|
||||
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"
|
||||
done
|
||||
# textInfo "Make sure your team can create a Support case with AWS "
|
||||
# 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 Group / User / Role "
|
||||
textFail "Support Policy not applied to any Role "
|
||||
fi
|
||||
done
|
||||
else
|
||||
|
||||
@@ -22,7 +22,7 @@ check121(){
|
||||
LIST_USERS_KEY1_ACTIVE=$(for user in $LIST_USERS_KEY1_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$9 }'|grep "true$"|awk '{ print $1 }'|sed 's/[[:blank:]]+/,/g' ; done)
|
||||
if [[ $LIST_USERS_KEY1_ACTIVE ]]; then
|
||||
for user in $LIST_USERS_KEY1_ACTIVE; do
|
||||
textInfo "$user has never used Access Key 1"
|
||||
textFail "$user has never used Access Key 1"
|
||||
done
|
||||
else
|
||||
textPass "No users found with Access Key 1 never used"
|
||||
@@ -32,7 +32,7 @@ check121(){
|
||||
LIST_USERS_KEY2_ACTIVE=$(for user in $LIST_USERS_KEY2_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$14 }'|grep "true$" |awk '{ print $1 }' ; done)
|
||||
if [[ $LIST_USERS_KEY2_ACTIVE ]]; then
|
||||
for user in $LIST_USERS_KEY2_ACTIVE; do
|
||||
textInfo "$user has never used Access Key 2"
|
||||
textFail "$user has never used Access Key 2"
|
||||
done
|
||||
else
|
||||
textPass "No users found with Access Key 2 never used"
|
||||
|
||||
@@ -22,7 +22,7 @@ check122(){
|
||||
for policy in $LIST_CUSTOM_POLICIES; do
|
||||
POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}')
|
||||
POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}')
|
||||
POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "PolicyVersion.Document.Statement[?Action!=null]|[?Effect == 'Allow' && contains(Resource, '*') && contains (Action, '*')]" $PROFILE_OPT --region $REGION)
|
||||
POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "[PolicyVersion.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION)
|
||||
if [[ $POLICY_WITH_FULL ]]; then
|
||||
POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $POLICY_ARN"
|
||||
fi
|
||||
@@ -30,7 +30,7 @@ check122(){
|
||||
if [[ $POLICIES_ALLOW_LIST ]]; then
|
||||
textInfo "List of custom policies: "
|
||||
for policy in $POLICIES_ALLOW_LIST; do
|
||||
textInfo "Policy $policy allows \"*:*\""
|
||||
textFail "Policy $policy allows \"*:*\""
|
||||
done
|
||||
else
|
||||
textPass "No custom policy found that allow full \"*:*\" administrative privileges"
|
||||
|
||||
@@ -15,18 +15,25 @@ CHECK_TYPE_check21="LEVEL1"
|
||||
CHECK_ALTERNATE_check201="check21"
|
||||
|
||||
check21(){
|
||||
trail_count=0
|
||||
# "Ensure CloudTrail is enabled in all regions (Scored)"
|
||||
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text)
|
||||
if [[ $LIST_OF_TRAILS ]];then
|
||||
for trail in $LIST_OF_TRAILS;do
|
||||
MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail)
|
||||
if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then
|
||||
textFail "$trail trail in $REGION is not enabled in multi region mode"
|
||||
else
|
||||
textPass "$trail trail in $REGION is enabled for all regions"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudTrail trails found!"
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].Name' --output text --no-include-shadow-trails)
|
||||
if [[ $LIST_OF_TRAILS ]];then
|
||||
for trail in $LIST_OF_TRAILS;do
|
||||
trail_count=$((trail_count + 1))
|
||||
MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail)
|
||||
if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then
|
||||
textFail "$trail trail in $regx is not enabled in multi region mode"
|
||||
else
|
||||
textPass "$trail trail in $regx is enabled for all regions"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $trail_count == 0 ]]; then
|
||||
textFail "No CloudTrail trails were found in the account"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,18 @@ CHECK_ALTERNATE_check202="check22"
|
||||
|
||||
check22(){
|
||||
# "Ensure CloudTrail log file validation is enabled (Scored)"
|
||||
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text)
|
||||
if [[ $LIST_OF_TRAILS ]];then
|
||||
for trail in $LIST_OF_TRAILS;do
|
||||
LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail)
|
||||
if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then
|
||||
textFail "$trail trail in $REGION has not log file validation enabled"
|
||||
else
|
||||
textPass "$trail trail in $REGION has log file validation enabled"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudTrail trails found!"
|
||||
fi
|
||||
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].Name' --output text --no-include-shadow-trails)
|
||||
if [[ $LIST_OF_TRAILS ]];then
|
||||
for trail in $LIST_OF_TRAILS;do
|
||||
LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail)
|
||||
if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then
|
||||
textFail "$trail trail in $regx has not log file validation enabled"
|
||||
else
|
||||
textPass "$trail trail in $regx has log file validation enabled"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -17,10 +17,14 @@ CHECK_ALTERNATE_check203="check23"
|
||||
check23(){
|
||||
# "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)"
|
||||
CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION)
|
||||
if [[ $CLOUDTRAILBUCKET ]];then
|
||||
if [[ $CLOUDTRAILBUCKET ]]; then
|
||||
for bucket in $CLOUDTRAILBUCKET;do
|
||||
CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text)
|
||||
if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]];then
|
||||
CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text 2>&1)
|
||||
if [[ $(echo "$CLOUDTRAILBUCKET_HASALLPERMISIONS" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Acl for $bucket"
|
||||
continue
|
||||
fi
|
||||
if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]]; then
|
||||
textFail "check your $bucket CloudTrail bucket ACL and Policy!"
|
||||
else
|
||||
textPass "Bucket $bucket is set correctly"
|
||||
|
||||
@@ -16,17 +16,36 @@ CHECK_ALTERNATE_check206="check26"
|
||||
|
||||
check26(){
|
||||
# "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)"
|
||||
CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION)
|
||||
if [[ $CLOUDTRAILBUCKET ]];then
|
||||
for bucket in $CLOUDTRAILBUCKET;do
|
||||
CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' --output text|grep -v None)
|
||||
if [[ $CLOUDTRAILBUCKET_LOGENABLED ]];then
|
||||
textPass "Bucket access logging enabled in $bucket"
|
||||
|
||||
CLOUDTRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[*].Name' --output text| tr '\011' '\012' | awk -F: '{print $1}')
|
||||
|
||||
if [[ $CLOUDTRAILS ]]; then
|
||||
for trail in $CLOUDTRAILS; do
|
||||
CLOUDTRAIL_ACCOUNT_ID=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[*].TrailARN' --output text | tr '\011' '\012' | grep "$trail" | awk -F: '{ print $5 }' | head -n 1)
|
||||
CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].[Name, S3BucketName]' --output text | tr '\011' ':' | grep "$trail" | awk -F: '{ print $2 }' )
|
||||
|
||||
if [[ $CLOUDTRAILBUCKET ]]; then
|
||||
bucket=$CLOUDTRAILBUCKET
|
||||
if [ "$CLOUDTRAIL_ACCOUNT_ID" == "$ACCOUNT_NUM" ]; then
|
||||
CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' --output text 2>&1)
|
||||
if [[ $(echo "$CLOUDTRAILBUCKET_LOGENABLED" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Logging for $bucket"
|
||||
continue
|
||||
fi
|
||||
if [[ $CLOUDTRAILBUCKET_LOGENABLED != "null" ]]; then
|
||||
textPass "Bucket access logging enabled in CloudTrail S3 bucket $bucket for $trail"
|
||||
else
|
||||
textFail "Bucket access logging is not enabled in CloudTrail S3 bucket $bucket for $trail"
|
||||
fi
|
||||
else
|
||||
textFail "access logging is not enabled in $bucket CloudTrail S3 bucket!"
|
||||
textInfo "CloudTrail S3 bucket $bucket for trail $trail is not in current account"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "CloudTrail bucket not found!"
|
||||
fi
|
||||
else
|
||||
textFail "CloudTrail bucket not found!"
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
textFail "No CloudWatch group found and no CloudTrail bucket"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -15,15 +15,18 @@ CHECK_TYPE_check29="LEVEL2"
|
||||
CHECK_ALTERNATE_check209="check29"
|
||||
|
||||
check29(){
|
||||
# "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)"
|
||||
# "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)"
|
||||
for regx in $REGIONS; do
|
||||
CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].FlowLogId' --output text)
|
||||
if [[ $CHECK_FL ]];then
|
||||
for FL in $CHECK_FL;do
|
||||
textPass "VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx"
|
||||
done
|
||||
else
|
||||
textFail "No VPCFlowLog has been found in Region $regx" "$regx"
|
||||
fi
|
||||
AVAILABLE_VPC=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[?State==`available`].VpcId' --output text)
|
||||
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)
|
||||
if [[ $CHECK_FL ]];then
|
||||
for FL in $CHECK_FL;do
|
||||
textPass "VPC $vpcx: VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx"
|
||||
done
|
||||
else
|
||||
textFail "VPC $vpcx: No VPCFlowLog has been found in Region $regx" "$regx"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/MyCloudTrailLG \
|
||||
# --filter-name AWSAuthorizationFailures \
|
||||
# --filter-pattern '{ $.errorCode = "*UnauthorizedOperation" || $.errorCode = "AccessDenied*" }' \
|
||||
# --metric-transformations metricName=AuthorizationFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name "Authorization Failures" \
|
||||
# --alarm-description "Alarm triggered when unauthorized API calls are made" \
|
||||
# --metric-name AuthorizationFailureCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check31="3.1,3.01"
|
||||
CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)"
|
||||
@@ -15,49 +40,5 @@ CHECK_TYPE_check31="LEVEL1"
|
||||
CHECK_ALTERNATE_check301="check31"
|
||||
|
||||
check31(){
|
||||
# "Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text| tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
#METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | awk '/UnauthorizedOperation/ || /AccessDenied/ {print $3}')
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --output text | grep METRICFILTERS | awk 'BEGIN {IGNORECASE=1}; /UnauthorizedOperation/ || /AccessDenied/ {print $3};')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
for metric in $METRICFILTER_SET; do
|
||||
metric_name=$($AWSCLI logs describe-metric-filters $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --log-group-name $group --filter-name-prefix $metric --output text --query 'metricFilters[0].metricTransformations[0].metricName')
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[?MetricName==`'$metric_name'`]' --output text)
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
CHECK31OK="$CHECK31OK $group:$metric"
|
||||
else
|
||||
CHECK31WARN="$CHECK31WARN $group:$metric"
|
||||
fi
|
||||
done
|
||||
else
|
||||
CHECK31WARN="$CHECK31WARN $group"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $CHECK31OK ]]; then
|
||||
for group in $CHECK31OK; do
|
||||
metric=${group#*:}
|
||||
group=${group%:*}
|
||||
textPass "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied"
|
||||
done
|
||||
fi
|
||||
if [[ $CHECK31WARN ]]; then
|
||||
for group in $CHECK31WARN; do
|
||||
case $group in
|
||||
*:*) metric=${group#*:}
|
||||
group=${group%:*}
|
||||
textFail "CloudWatch group $group found with metric filter $metric but no alarms associated"
|
||||
;;
|
||||
*) textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
esac
|
||||
done
|
||||
fi
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.errorCode\s*=\s*"\*UnauthorizedOperation".+\$\.errorCode\s*=\s*"AccessDenied\*"'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name SecurityGroupConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) }' \
|
||||
# --metric-transformations metricName=SecurityGroupEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name SecurityGroupConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS security group(s) config changes." \
|
||||
# --metric-name SecurityGroupEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check310="3.10"
|
||||
CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)"
|
||||
@@ -15,26 +40,5 @@ CHECK_TYPE_check310="LEVEL2"
|
||||
CHECK_ALTERNATE_check310="check310"
|
||||
|
||||
check310(){
|
||||
# "Ensure a log metric filter and alarm exist for security group changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'AuthorizeSecurityGroupIngress.*AuthorizeSecurityGroupEgress.*RevokeSecurityGroupIngress.*RevokeSecurityGroupEgress.*CreateSecurityGroup.*DeleteSecurityGroup')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /SecurityGroup/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for security group changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name NetworkACLConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }' \
|
||||
# --metric-transformations metricName=NetworkAclEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name NetworkACLConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS Network ACL(s) config changes." \
|
||||
# --metric-name NetworkAclEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check311="3.11"
|
||||
CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)"
|
||||
@@ -15,26 +40,5 @@ CHECK_TYPE_check311="LEVEL2"
|
||||
CHECK_ALTERNATE_check311="check311"
|
||||
|
||||
check311(){
|
||||
# "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateNetworkAcl.*CreateNetworkAclEntry.*DeleteNetworkAcl.*DeleteNetworkAclEntry.*ReplaceNetworkAclEntry.*ReplaceNetworkAclAssociation')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /NetworkAcl/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for changes to NACLs"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name VPCGatewayConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }' \
|
||||
# --metric-transformations metricName=GatewayEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name VPCGatewayConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by VPC Customer/Internet Gateway changes." \
|
||||
# --metric-name GatewayEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check312="3.12"
|
||||
CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)"
|
||||
@@ -15,26 +40,5 @@ CHECK_TYPE_check312="LEVEL1"
|
||||
CHECK_ALTERNATE_check312="check312"
|
||||
|
||||
check312(){
|
||||
# "Ensure a log metric filter and alarm exist for changes to network gateways (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateCustomerGateway.*DeleteCustomerGateway.*AttachInternetGateway.*CreateInternetGateway.*DeleteInternetGateway.*DetachInternetGateway')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /InternetGateway/ || /CustomerGateway/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for changes to network gateways"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name RouteTableConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }' \
|
||||
# --metric-transformations metricName=RouteTableEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name RouteTableConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS Route Table config changes." \
|
||||
# --metric-name RouteTableEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check313="3.13"
|
||||
CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)"
|
||||
@@ -15,26 +40,5 @@ CHECK_TYPE_check313="LEVEL1"
|
||||
CHECK_ALTERNATE_check313="check313"
|
||||
|
||||
check313(){
|
||||
# "Ensure a log metric filter and alarm exist for route table changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateRoute.*CreateRouteTable.*ReplaceRoute.*ReplaceRouteTableAssociation.*DeleteRouteTable.*DeleteRoute.*DisassociateRouteTable')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /Route/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for route table changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name VPCNetworkConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }' \
|
||||
# --metric-transformations metricName=VpcEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name VPCNetworkConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS VPC(s) environment config changes." \
|
||||
# --metric-name VpcEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check314="3.14"
|
||||
CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)"
|
||||
@@ -15,26 +40,5 @@ CHECK_TYPE_check314="LEVEL1"
|
||||
CHECK_ALTERNATE_check314="check314"
|
||||
|
||||
check314(){
|
||||
# "Ensure a log metric filter and alarm exist for VPC changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | grep $group | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateVpc.*DeleteVpc.*ModifyVpcAttribute.*AcceptVpcPeeringConnection.*CreateVpcPeeringConnection.*DeleteVpcPeeringConnection.*RejectVpcPeeringConnection.*AttachClassicLinkVpc.*DetachClassicLinkVpc.*DisableVpcClassicLink.*EnableVpcClassicLink')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /VPC/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for VPC changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name ConsoleSignInWithoutMfaCount \
|
||||
# --filter-pattern '{ $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed != "Yes" }' \
|
||||
# --metric-transformations metricName=ConsoleSignInWithoutMfaCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name ConsoleSignInWithoutMfaAlarm \
|
||||
# --alarm-description "Triggered by sign-in requests made without MFA." \
|
||||
# --metric-name ConsoleSignInWithoutMfaCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check32="3.2,3.02"
|
||||
CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check32="LEVEL1"
|
||||
CHECK_ALTERNATE_check302="check32"
|
||||
|
||||
check32(){
|
||||
# "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' |grep filterPattern|grep MFAUsed| awk '/ConsoleLogin/ && (/additionalEventData.MFAUsed.*\!=.*\"Yes/) {print $1}')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /ConsoleLogin/ || /MFAUsed/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms set for sign-in Console without MFA enabled"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*"ConsoleLogin".+\$\.additionalEventData\.MFAUsed\s*!=\s*"Yes"'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name RootAccountUsage \
|
||||
# --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
|
||||
# --metric-transformations metricName=RootAccountUsageEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 \
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name RootAccountUsageAlarm \
|
||||
# --alarm-description "Triggered by AWS Root Account usage." \
|
||||
# --metric-name RootAccountUsageEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check33="3.3,3.03"
|
||||
CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check33="LEVEL1"
|
||||
CHECK_ALTERNATE_check303="check33"
|
||||
|
||||
check33(){
|
||||
# "Ensure a log metric filter and alarm exist for usage of root account (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION |grep -E 'userIdentity.*Root.*AwsServiceEvent')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | tr '[:upper:]' '[:lower:]'| grep -Ei 'userIdentity|Root|AwsServiceEvent')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms set for usage of root account"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name IAMAuthConfigChanges \
|
||||
# --filter-pattern '{ ($.eventName = DeleteGroupPolicy) || ($.eventName = DeleteRolePolicy) || ($.eventName = DeleteUserPolicy) || ($.eventName = PutGroupPolicy) || ($.eventName = PutRolePolicy) || ($.eventName = PutUserPolicy) || ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = CreatePolicyVersion) || ($.eventName = DeletePolicyVersion) || ($.eventName = AttachRolePolicy) || ($.eventName = DetachRolePolicy) || ($.eventName = AttachUserPolicy) || ($.eventName = DetachUserPolicy) || ($.eventName = AttachGroupPolicy) || ($.eventName = DetachGroupPolicy) }' \
|
||||
# --metric-transformations metricName=IAMPolicyEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name IAMAuthorizationActivityAlarm \
|
||||
# --alarm-description "Triggered by AWS IAM authorization config changes." \
|
||||
# --metric-name IAMPolicyEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check34="3.4,3.04"
|
||||
CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check34="LEVEL1"
|
||||
CHECK_ALTERNATE_check304="check34"
|
||||
|
||||
check34(){
|
||||
# "Ensure a log metric filter and alarm exist for IAM policy changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'DeleteGroupPolicy.*DeleteRolePolicy.*DeleteUserPolicy.*PutGroupPolicy.*PutRolePolicy.*PutUserPolicy.*CreatePolicy.*DeletePolicy.*CreatePolicyVersion.*DeletePolicyVersion.*AttachRolePolicy.*DetachRolePolicy.*AttachUserPolicy.*DetachUserPolicy.*AttachGroupPolicy.*DetachGroupPolicy')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DeletePolicy/ || /DeletePolicies/ || /Policies/ || /Policy/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for IAM policy changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/MyCloudTrailLG \
|
||||
# --filter-name AWSCloudTrailChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' \
|
||||
# --metric-transformations metricName=CloudTrailEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name "CloudTrail Changes" \
|
||||
# --alarm-description "Triggered by AWS CloudTrail configuration changes." \
|
||||
# --metric-name CloudTrailEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check35="3.5,3.05"
|
||||
CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check35="LEVEL1"
|
||||
CHECK_ALTERNATE_check305="check35"
|
||||
|
||||
check35(){
|
||||
# "Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateTrail.*UpdateTrail.*DeleteTrail.*StartLogging.*StopLogging')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /TrailChange/ || /Trails/ || /CreateTrail/ || /UpdateTrail/ || /DeleteTrail/ || /StartLogging/ || /StopLogging/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for CloudTrail configuration changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/MyCloudTrailLG \
|
||||
# --filter-name AWSConsoleSignInFailures \
|
||||
# --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed authentication") }' \
|
||||
# --metric-transformations metricName=ConsoleSigninFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name "Console Sign-in Failures" \
|
||||
# --alarm-description "AWS Management Console Sign-in Failure Alarm." \
|
||||
# --metric-name ConsoleSigninFailureCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 3 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check36="3.6,3.06"
|
||||
CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check36="LEVEL2"
|
||||
CHECK_ALTERNATE_check306="check36"
|
||||
|
||||
check36(){
|
||||
# "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'ConsoleLogin.*Failed')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /FailedLogin/ || /ConsoleLogin/ || /Failed/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for AWS Management Console authentication failures"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventName\s*=\s*ConsoleLogin.+\$\.errorMessage\s*=\s*"Failed authentication"'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name AWSCMKChanges \
|
||||
# --filter-pattern '{ ($.eventSource = kms.amazonaws.com) && (($.eventName = DisableKey) || ($.eventName = ScheduleKeyDeletion)) }' \
|
||||
# --metric-transformations metricName=CMKEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name AWSCMKChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS CMK changes." \
|
||||
# --metric-name CMKEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check37="3.7,3.07"
|
||||
CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check37="LEVEL2"
|
||||
CHECK_ALTERNATE_check307="check37"
|
||||
|
||||
check37(){
|
||||
# "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'kms.amazonaws.com.*DisableKey.*ScheduleKeyDeletion')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DisableKey/ || /ScheduleKeyDeletion/ || /kms/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for changes of customer created CMKs"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name S3BucketConfigChanges \
|
||||
# --filter-pattern '{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }' \
|
||||
# --metric-transformations metricName=S3BucketEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name S3BucketConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS S3 Bucket config changes." \
|
||||
# --metric-name S3BucketEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check38="3.8,3.08"
|
||||
CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check38="LEVEL1"
|
||||
CHECK_ALTERNATE_check308="check38"
|
||||
|
||||
check38(){
|
||||
# "Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 's3.amazonaws.com.*PutBucketAcl.*PutBucketPolicy.*PutBucketCors.*PutBucketLifecycle.*PutBucketReplication.*DeleteBucketPolicy.*DeleteBucketCors.*DeleteBucketLifecycle.*DeleteBucketReplication')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /S3/ || /BucketPolicy/ || /BucketPolicies/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for S3 bucket policy changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication'
|
||||
}
|
||||
|
||||
@@ -7,6 +7,31 @@
|
||||
#
|
||||
# You should have received a copy of the license along with this
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
#
|
||||
# Remediation:
|
||||
#
|
||||
# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
|
||||
#
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/CloudWatchLogGroup \
|
||||
# --filter-name AWSConfigChanges \
|
||||
# --filter-pattern '{ ($.eventSource = config.amazonaws.com) && (($.eventName = StopConfigurationRecorder)||($.eventName = DeleteDeliveryChannel)||($.eventName = PutDeliveryChannel)||($.eventName = PutConfigurationRecorder)) }' \
|
||||
# --metric-transformations metricName=ConfigEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
#
|
||||
# aws cloudwatch put-metric-alarm \
|
||||
# --region us-east-1 \
|
||||
# --alarm-name AWSConfigChangesAlarm \
|
||||
# --alarm-description "Triggered by AWS Config changes." \
|
||||
# --metric-name ConfigEventCount \
|
||||
# --namespace CloudTrailMetrics \
|
||||
# --statistic Sum \
|
||||
# --comparison-operator GreaterThanOrEqualToThreshold \
|
||||
# --evaluation-periods 1 \
|
||||
# --period 300 \
|
||||
# --threshold 1 \
|
||||
# --actions-enabled \
|
||||
# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic
|
||||
|
||||
CHECK_ID_check39="3.9,3.09"
|
||||
CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)"
|
||||
@@ -15,25 +40,5 @@ CHECK_TYPE_check39="LEVEL2"
|
||||
CHECK_ALTERNATE_check309="check39"
|
||||
|
||||
check39(){
|
||||
# "Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)"
|
||||
CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' '
|
||||
' | awk -F: '{ print $7 }')
|
||||
if [[ $CLOUDWATCH_GROUP ]];then
|
||||
for group in $CLOUDWATCH_GROUP; do
|
||||
CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }' | head -n 1)
|
||||
METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'config.amazonaws.com.*StopConfigurationRecorder.*DeleteDeliveryChannel.*PutDeliveryChannel.*PutConfigurationRecorder')
|
||||
if [[ $METRICFILTER_SET ]];then
|
||||
HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /config/ || /ConfigurationRecorder/ || /DeliveryChannel/;')
|
||||
if [[ $HAS_ALARM_ASSOCIATED ]];then
|
||||
textPass "CloudWatch group $group found with metric filters and alarms for AWS Config configuration changes"
|
||||
else
|
||||
textFail "CloudWatch group $group found with metric filters but no alarms associated"
|
||||
fi
|
||||
else
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
fi
|
||||
check3x '\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder'
|
||||
}
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
CHECK_ID_check41="4.1,4.01"
|
||||
CHECK_TITLE_check41="[check41] Ensure no security groups allow ingress from 0.0.0.0/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 (Scored)"
|
||||
CHECK_SCORED_check41="SCORED"
|
||||
CHECK_TYPE_check41="LEVEL2"
|
||||
CHECK_ALTERNATE_check401="check41"
|
||||
|
||||
check41(){
|
||||
# "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)"
|
||||
# "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 22 (Scored)"
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
CHECK_ID_check42="4.2,4.02"
|
||||
CHECK_TITLE_check42="[check42] Ensure no security groups allow ingress from 0.0.0.0/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 (Scored)"
|
||||
CHECK_SCORED_check42="SCORED"
|
||||
CHECK_TYPE_check42="LEVEL2"
|
||||
CHECK_ALTERNATE_check402="check42"
|
||||
|
||||
check42(){
|
||||
# "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)"
|
||||
# "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389 (Scored)"
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
|
||||
@@ -17,11 +17,14 @@ CHECK_ALTERNATE_check403="check43"
|
||||
check43(){
|
||||
# "Ensure the default security group of every VPC restricts all traffic (Scored)"
|
||||
for regx in $REGIONS; do
|
||||
CHECK_SGDEFAULT=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |grep 0.0.0.0)
|
||||
if [[ $CHECK_SGDEFAULT ]];then
|
||||
textFail "Default Security Groups found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx"
|
||||
else
|
||||
textPass "No Default Security Groups open to 0.0.0.0 found in Region $regx" "$regx"
|
||||
fi
|
||||
CHECK_SGDEFAULT_IDS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].GroupId[]' --output text)
|
||||
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 '0.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"
|
||||
else
|
||||
textPass "No Default Security Groups ($CHECK_SGDEFAULT_ID) open to 0.0.0.0 found in Region $regx" "$regx"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
@@ -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,7.01"
|
||||
CHECK_TITLE_extra71="[extra71] Ensure users 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 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra71="NOT_SCORED"
|
||||
CHECK_TYPE_extra71="EXTRA"
|
||||
CHECK_ALTERNATE_extra701="extra71"
|
||||
@@ -19,7 +19,7 @@ CHECK_ALTERNATE_check71="extra71"
|
||||
CHECK_ALTERNATE_check701="extra71"
|
||||
|
||||
extra71(){
|
||||
# "Ensure users 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 (Not Scored) (Not part of CIS benchmark)"
|
||||
ADMIN_GROUPS=''
|
||||
AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --query 'Groups[].GroupName')
|
||||
for grp in $AWS_GROUPS; do
|
||||
|
||||
@@ -18,7 +18,7 @@ CHECK_ALTERNATE_check711="extra711"
|
||||
|
||||
extra711(){
|
||||
# "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)"
|
||||
textInfo "Looking for Reshift clusters in all regions... "
|
||||
textInfo "Looking for Redshift clusters in all regions... "
|
||||
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
|
||||
|
||||
@@ -22,7 +22,7 @@ extra712(){
|
||||
textInfo "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 "Macie related IAM roles exist so it might be enabled. Check it out manually."
|
||||
else
|
||||
textFail "No Macie related IAM roles found. It is most likely not to be enabled"
|
||||
fi
|
||||
|
||||
@@ -19,18 +19,24 @@ CHECK_ALTERNATE_check713="extra713"
|
||||
extra713(){
|
||||
# "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text |cut -f2)
|
||||
if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then
|
||||
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"
|
||||
LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text --query DetectorIds[*] 2> /dev/null)
|
||||
RESULT=$?
|
||||
if [ $RESULT -eq 0 ];then
|
||||
if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then
|
||||
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"
|
||||
else
|
||||
textFail "$regx: GuardDuty detector $detector configured but suspended" "$regx"
|
||||
fi
|
||||
done <<< "$LIST_OF_GUARDDUTY_DETECTORS"
|
||||
else
|
||||
textFail "$regx: GuardDuty detector $detector configured but suspended" "$regx"
|
||||
fi
|
||||
done <<< "$LIST_OF_GUARDDUTY_DETECTORS"
|
||||
else
|
||||
textFail "$regx: GuardDuty detector not configured!" "$regx"
|
||||
fi
|
||||
textFail "$regx: GuardDuty detector not configured!" "$regx"
|
||||
fi
|
||||
else
|
||||
# if list-detectors return any error
|
||||
textInfo "$regx: GuardDuty not checked" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
}
|
||||
@@ -18,19 +18,17 @@ CHECK_ALTERNATE_check714="extra714"
|
||||
|
||||
extra714(){
|
||||
# "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --region $regx --query 'DistributionList.Items[].Id' --output text |grep -v "^None")
|
||||
if [[ $LIST_OF_DISTRIBUTIONS ]]; then
|
||||
for cdn in $LIST_OF_DISTRIBUTIONS;do
|
||||
CDN_LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --region $regx --id "$cdn" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true)
|
||||
if [[ $CDN_LOG_ENABLED ]];then
|
||||
textPass "$regx: CDN $cdn logging enabled" "$regx"
|
||||
else
|
||||
textFail "$regx: CDN $cdn logging disabled!" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No CDN configured" "$regx"
|
||||
fi
|
||||
done
|
||||
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"
|
||||
else
|
||||
textFail "CloudFront distribution $dist has logging disabled"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "No CloudFront distributions found"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ extra716(){
|
||||
TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX)
|
||||
$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 Principal as *
|
||||
CHECK_ES_DOMAIN_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*)
|
||||
CHECK_ES_DOMAIN_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and .Condition == null)')
|
||||
if [[ $CHECK_ES_DOMAIN_ALLUSERS_POLICY ]];then
|
||||
textFail "$regx: $domain policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx"
|
||||
else
|
||||
@@ -36,9 +36,10 @@ extra716(){
|
||||
else
|
||||
textPass "$regx: $domain is in a VPC" "$regx"
|
||||
fi
|
||||
rm -f $TEMP_POLICY_FILE
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No Elasticsearch Service domain found" "$regx"
|
||||
fi
|
||||
textInfo "$regx: No Elasticsearch Service domain found" "$regx"
|
||||
rm -fr $TEMP_POLICY_FILE
|
||||
done
|
||||
}
|
||||
|
||||
@@ -21,11 +21,15 @@ extra718(){
|
||||
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
|
||||
if [[ $LIST_OF_BUCKETS ]]; then
|
||||
for bucket in $LIST_OF_BUCKETS;do
|
||||
BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$")
|
||||
if [[ $BUCKET_SERVER_LOG_ENABLED ]];then
|
||||
textPass "Bucket $bucket has server access logging enabled"
|
||||
else
|
||||
BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text 2>&1)
|
||||
if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Logging for $bucket"
|
||||
continue
|
||||
fi
|
||||
if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep "^None$") ]]; then
|
||||
textFail "Bucket $bucket has server access logging disabled!"
|
||||
else
|
||||
textPass "Bucket $bucket has server access logging enabled"
|
||||
fi
|
||||
done
|
||||
else
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
# 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 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 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra719="NOT_SCORED"
|
||||
CHECK_TYPE_extra719="EXTRA"
|
||||
CHECK_ALTERNATE_check719="extra719"
|
||||
|
||||
extra719(){
|
||||
# "Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)"
|
||||
LIST_OF_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT --query HostedZones[*].Id --output text|xargs -n1)
|
||||
# You can't create a query logging config for a private hosted zone.
|
||||
LIST_OF_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT | jq -r ".HostedZones[] | select(.Config.PrivateZone == false) | .Id")
|
||||
if [[ $LIST_OF_HOSTED_ZONES ]]; then
|
||||
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 hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED"
|
||||
textPass "Route53 public hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED"
|
||||
else
|
||||
textFail "Route53 hosted zone Id $hostedzoneid has query logging disabled!"
|
||||
textFail "Route53 public hosted zone Id $hostedzoneid has query logging disabled!"
|
||||
fi
|
||||
done
|
||||
else
|
||||
|
||||
@@ -25,7 +25,7 @@ extra720(){
|
||||
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text)
|
||||
if [[ $LIST_OF_TRAILS ]]; then
|
||||
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:lambda.*function:$lambdafunction$")
|
||||
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:lambda.*function:$lambdafunction$|^arn:aws:lambda$")
|
||||
if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then
|
||||
textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx"
|
||||
else
|
||||
|
||||
@@ -26,11 +26,11 @@ extra722(){
|
||||
CHECK_STAGES_NAME=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[*].stageName" --output text)
|
||||
if [[ $CHECK_STAGES_NAME ]];then
|
||||
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 $1" log level "$6}')
|
||||
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 has stage logging enabled for $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"
|
||||
else
|
||||
textFail "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx"
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $apigwid in $stagname has logging disabled" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
|
||||
@@ -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 are public (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_TITLE_extra723="[extra723] Check if RDS Snapshots and Cluster Snapshots are public (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra723="NOT_SCORED"
|
||||
CHECK_TYPE_extra723="EXTRA"
|
||||
CHECK_ALTERNATE_check723="extra723"
|
||||
|
||||
@@ -20,12 +20,32 @@ CHECK_ALTERNATE_check726="extra726"
|
||||
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)
|
||||
TA_CHECKS_ID=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query checks[*].id --output text 2>&1)
|
||||
if [[ $(echo "$TA_CHECKS_ID" | grep SubscriptionRequiredException) ]]; then
|
||||
textInfo "Trusted Advisor requires AWS Premium Support Subscription"
|
||||
return
|
||||
fi
|
||||
|
||||
for checkid in $TA_CHECKS_ID; do
|
||||
QUERY_RESULT_NO_OK=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text | grep -v "ok" )
|
||||
if [[ $QUERY_RESULT_NO_OK ]]; then
|
||||
TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text)
|
||||
textFail "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_RESULT_NO_OK"
|
||||
fi
|
||||
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)
|
||||
# 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"
|
||||
;;
|
||||
"error")
|
||||
textFail "Trusted Advisor check $TA_CHECKS_NAME is in error state $QUERY_TA_CHECK_RESULT"
|
||||
;;
|
||||
"warning")
|
||||
textInfo "Trusted Advisor check $TA_CHECKS_NAME is in warning state $QUERY_TA_CHECK_RESULT"
|
||||
;;
|
||||
"not_available")
|
||||
textInfo "Trusted Advisor check $TA_CHECKS_NAME is in not_available state $QUERY_TA_CHECK_RESULT"
|
||||
;;
|
||||
"*")
|
||||
textFail "Trusted Advisor check $TA_CHECKS_NAME is in unknown state $QUERY_TA_CHECK_RESULT"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
@@ -22,18 +22,25 @@ extra727(){
|
||||
LIST_SQS=$($AWSCLI sqs list-queues $PROFILE_OPT --region $regx --query QueueUrls --output text |grep -v ^None)
|
||||
if [[ $LIST_SQS ]]; then
|
||||
for queue in $LIST_SQS; do
|
||||
# check if the policy has Principal as *
|
||||
SQS_TO_CHECK=$($AWSCLI sqs get-queue-attributes --queue-url $queue $PROFILE_OPT --region $regx --attribute-names All --query Attributes.Policy --output text | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ || /Condition/ && !skip { print } { skip = /Deny/} ')
|
||||
PUBLIC_SQS_WCONDITION=$(echo $SQS_TO_CHECK|grep Condition)
|
||||
if [[ $PUBLIC_SQS_WCONDITION ]]; then
|
||||
textInfo "$regx: SQS queue $queue has a Condition" "$regx"
|
||||
else
|
||||
PUBLIC_SQS=$(echo $SQS_TO_CHECK|grep \"Principal|grep \*)
|
||||
if [[ $PUBLIC_SQS ]]; then
|
||||
textFail "$regx: SQS queue $queue seems to be public (Principal: \"*\")" "$regx"
|
||||
SQS_POLICY=$($AWSCLI sqs get-queue-attributes --queue-url $queue $PROFILE_OPT --region $regx --attribute-names All --query Attributes.Policy)
|
||||
if [[ "$SQS_POLICY" != "null" ]]; then
|
||||
SQS_POLICY_ALLOW_ALL=$(echo $SQS_POLICY \
|
||||
| jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*")')
|
||||
if [[ $SQS_POLICY_ALLOW_ALL ]]; then
|
||||
SQS_POLICY_ALLOW_ALL_WITHOUT_CONDITION=$(echo $SQS_POLICY \
|
||||
| jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*") | select(has("Condition") | not)')
|
||||
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"
|
||||
else
|
||||
textInfo "$regx: SQS $queue queue policy with public access but has a Condition" "$regx"
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: SQS queue $queue seems correct" "$regx"
|
||||
textPass "$regx: SQS $queue queue without public access" "$regx"
|
||||
fi
|
||||
else
|
||||
textPass "$regx: SQS $queue queue without policy" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
# 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_extra73="7.3,7.03"
|
||||
CHECK_TITLE_extra73="[extra73] Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra73="NOT_SCORED"
|
||||
@@ -18,113 +19,136 @@ CHECK_ALTERNATE_extra703="extra73"
|
||||
CHECK_ALTERNATE_check73="extra73"
|
||||
CHECK_ALTERNATE_check703="extra73"
|
||||
|
||||
# Improved and simplified check on Nov 18th 2018 due to a new bucket attribute
|
||||
# called PolicyStatus, not available in all regions yet.
|
||||
|
||||
# extra73(){
|
||||
# ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text)
|
||||
# for bucket in $ALL_BUCKETS_LIST; do
|
||||
# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text)
|
||||
# if [[ "None" == $BUCKET_LOCATION ]]; then
|
||||
# BUCKET_LOCATION="us-east-1"
|
||||
# fi
|
||||
# if [[ "EU" == $BUCKET_LOCATION ]]; then
|
||||
# BUCKET_LOCATION="eu-west-1"
|
||||
# fi
|
||||
# Verified with AWS support that if get-bucket-acl doesn't return a grant
|
||||
# for All and get-bucket-policy-status returns IsPublic false or bad request
|
||||
# (no policy) then the bucket can be considered not public - though
|
||||
# individual objects may still be. If in addition put-public-access-block is
|
||||
# used to set IgnorePublicAcls and RestrictPublicBuckets to true then that
|
||||
# causes Amazon S3 to ignore all public ACLs on a bucket and any objects that
|
||||
# it contains.
|
||||
#
|
||||
# BUCKET_POLICY_STATUS=$($AWSCLI s3api get-bucket-policy-status --bucket $bucket --query PolicyStatus.IsPublic --output text | grep False)
|
||||
# if [[ $BUCKET_POLICY_STATUS ]];then
|
||||
# textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$regx"
|
||||
# else
|
||||
# textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$regx"
|
||||
# fi
|
||||
# done
|
||||
# }
|
||||
|
||||
# This check does not address legacy ACLs or policies that would give
|
||||
# public access if not blocked at account or bucket level, instead it tries
|
||||
# to reward the use of more broadly restrictive controls with quicker and less
|
||||
# computational intensive checks.
|
||||
#
|
||||
# If we are assembling an inventory then maybe that is not what we want but
|
||||
# for day to day usage that is probably desirable.
|
||||
|
||||
extra73(){
|
||||
textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... "
|
||||
ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text)
|
||||
|
||||
#
|
||||
# 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 Trying to Get Public Access Block for $bucket"
|
||||
return
|
||||
fi
|
||||
if [[ $(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | grep NoSuchPublicAccessBlockConfiguration) ]]; then
|
||||
ACCOUNTIGNOREPUBLICACLS=""
|
||||
ACCOUNTRESTRICTPUBLICBUCKETS=""
|
||||
else
|
||||
ACCOUNTIGNOREPUBLICACLS=$(echo "$ACCOUNT_PUBLIC_ACCESS_BLOCK" | jq -r '.PublicAccessBlockConfiguration.IgnorePublicAcls')
|
||||
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"
|
||||
return
|
||||
fi
|
||||
|
||||
#
|
||||
# Otherwise start to iterate bucket
|
||||
#
|
||||
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"
|
||||
return
|
||||
fi
|
||||
if [[ "$ALL_BUCKETS_LIST" == "" ]]; then
|
||||
textInfo "No buckets found"
|
||||
return
|
||||
fi
|
||||
|
||||
for bucket in $ALL_BUCKETS_LIST; do
|
||||
BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text)
|
||||
|
||||
#
|
||||
# LOCATION - requests referencing buckets created after March 20, 2019
|
||||
# must be made to S3 endpoints in the same region as the bucket was
|
||||
# created.
|
||||
#
|
||||
BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text 2>&1)
|
||||
if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Location for $bucket"
|
||||
continue
|
||||
fi
|
||||
if [[ "None" == $BUCKET_LOCATION ]]; then
|
||||
BUCKET_LOCATION="us-east-1"
|
||||
fi
|
||||
if [[ "EU" == $BUCKET_LOCATION ]]; then
|
||||
BUCKET_LOCATION="eu-west-1"
|
||||
fi
|
||||
# check if AllUsers is in the ACL as Grantee
|
||||
CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE)
|
||||
CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL)
|
||||
# check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only
|
||||
CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE)
|
||||
CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL)
|
||||
# to prevent error NoSuchBucketPolicy first clean the output controlling stderr
|
||||
TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
|
||||
$AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null
|
||||
# check if the S3 policy has Principal as *
|
||||
CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*)
|
||||
if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then
|
||||
if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then
|
||||
textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx"
|
||||
fi
|
||||
if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then
|
||||
textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx"
|
||||
fi
|
||||
if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then
|
||||
textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx"
|
||||
fi
|
||||
else
|
||||
textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx"
|
||||
|
||||
#
|
||||
# If public ACLs disabled at bucket level then look no further
|
||||
#
|
||||
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"
|
||||
continue
|
||||
fi
|
||||
rm -fr $TEMP_POLICY_FILE
|
||||
if [[ $(echo "$BUCKET_PUBLIC_ACCESS_BLOCK" | grep NoSuchPublicAccessBlockConfiguration) ]]; then
|
||||
BUCKETIGNOREPUBLICACLS=""
|
||||
BUCKETRESTRICTPUBLICBUCKETS=""
|
||||
else
|
||||
BUCKETIGNOREPUBLICACLS=$(echo "$BUCKET_PUBLIC_ACCESS_BLOCK" | jq -r '.PublicAccessBlockConfiguration.IgnorePublicAcls')
|
||||
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"
|
||||
continue
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for public ACL grants
|
||||
#
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
continue
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for public access in policy
|
||||
#
|
||||
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"
|
||||
continue
|
||||
fi
|
||||
if [[ $(echo "$BUCKET_POLICY_STATUS" | grep NoSuchBucketPolicy) ]]; then
|
||||
BUCKET_POLICY_STATUS="False"
|
||||
fi
|
||||
|
||||
if [[ $BUCKET_POLICY_STATUS != "" && $BUCKET_POLICY_STATUS != "False" ]]; then
|
||||
textFail "$BUCKET_LOCATION: $bucket bucket is Public!" "$BUCKET_LOCATION"
|
||||
continue
|
||||
fi
|
||||
|
||||
textPass "$BUCKET_LOCATION: $bucket bucket is not Public" "$BUCKET_LOCATION"
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
# Then implementation below makes pararel checks but can reach AWS API limits
|
||||
# and eventually doesn't work as expected
|
||||
|
||||
# extra73(){
|
||||
# textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA"
|
||||
# textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... "
|
||||
# ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text)
|
||||
# for bucket in $ALL_BUCKETS_LIST; do
|
||||
# extra73Thread $bucket &
|
||||
# done
|
||||
# wait
|
||||
# }
|
||||
# extra73Thread(){
|
||||
# bucket=$1
|
||||
# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text)
|
||||
# if [[ "None" == $BUCKET_LOCATION ]]; then
|
||||
# BUCKET_LOCATION="us-east-1"
|
||||
# fi
|
||||
# if [[ "EU" == $BUCKET_LOCATION ]]; then
|
||||
# BUCKET_LOCATION="eu-west-1"
|
||||
# fi
|
||||
# # check if AllUsers is in the ACL as Grantee
|
||||
# CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE)
|
||||
# CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL)
|
||||
# # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only
|
||||
# CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE)
|
||||
# CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL)
|
||||
# # to prevent error NoSuchBucketPolicy first clean the output controlling stderr
|
||||
# TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
|
||||
# $AWSCLI s3api get-bucket-policy --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null
|
||||
# # check if the S3 policy has Principal as *
|
||||
# CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*)
|
||||
# if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then
|
||||
# if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then
|
||||
# textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx"
|
||||
# fi
|
||||
# if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then
|
||||
# textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx"
|
||||
# fi
|
||||
# if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then
|
||||
# textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx"
|
||||
# fi
|
||||
# else
|
||||
# textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx"
|
||||
# fi
|
||||
# rm -fr $TEMP_POLICY_FILE
|
||||
# }
|
||||
|
||||
@@ -25,7 +25,7 @@ extra730(){
|
||||
LIST_OF_ACM_CERTS=$($AWSCLI acm list-certificates $PROFILE_OPT --region $regx --query 'CertificateSummaryList[].CertificateArn' --output text)
|
||||
if [[ $LIST_OF_ACM_CERTS ]];then
|
||||
for cert in $LIST_OF_ACM_CERTS; do
|
||||
CERT_DATA=$($AWSCLI acm describe-certificate --certificate-arn $cert --query 'Certificate.[DomainName,NotAfter]' --output text)
|
||||
CERT_DATA=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert --query 'Certificate.[DomainName,NotAfter]' --output text)
|
||||
echo "$CERT_DATA" | while read FQDN NOTAFTER; do
|
||||
EXPIRES_DATE=$(timestamp_to_date $NOTAFTER)
|
||||
COUNTER_DAYS=$(how_many_days_from_today $EXPIRES_DATE)
|
||||
|
||||
@@ -22,23 +22,26 @@ extra731(){
|
||||
LIST_SNS=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --query Topics --output text |grep -v ^None)
|
||||
if [[ $LIST_SNS ]]; then
|
||||
for topic in $LIST_SNS; do
|
||||
# check if the policy has Principal as *
|
||||
SNS_TO_CHECK=$($AWSCLI sns get-topic-attributes --topic-arn $topic $PROFILE_OPT --region $regx --query Attributes.Policy --output text | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ || /Condition/ && !skip { print } { skip = /Deny/}')
|
||||
PUBLIC_SNS_WCONDITION=$(echo $SNS_TO_CHECK|grep Condition)
|
||||
SHORT_TOPIC=$(echo $topic| cut -d: -f6)
|
||||
if [[ $PUBLIC_SNS_WCONDITION ]]; then
|
||||
textInfo "$regx: SNS topic $SHORT_TOPIC has a Condition" "$regx"
|
||||
else
|
||||
PUBLIC_SNS=$(echo $SNS_TO_CHECK|grep \"Principal|grep \*)
|
||||
if [[ $PUBLIC_SNS ]]; then
|
||||
textFail "$regx: SNS topic $SHORT_TOPIC seems to be public (Principal: \"*\")" "$regx"
|
||||
SNS_POLICY=$($AWSCLI sns get-topic-attributes --topic-arn $topic $PROFILE_OPT --region $regx --query Attributes.Policy 2>/dev/null)
|
||||
SNS_POLICY_ALLOW_ALL=$(echo $SNS_POLICY \
|
||||
| jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*")')
|
||||
if [[ $SNS_POLICY_ALLOW_ALL ]]; then
|
||||
SNS_POLICY_ALLOW_ALL_WITHOUT_CONDITION=$(echo $SNS_POLICY \
|
||||
| jq '. | fromjson' | jq '.Statement[] | select(.Effect=="Allow") | select(.Principal=="*" or .Principal.AWS=="*" or .Principal.CanonicalUser=="*") | select(has("Condition") | not)')
|
||||
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" "$SHORT_TOPIC" "$regx"
|
||||
else
|
||||
textInfo "$regx: SNS topic $SHORT_TOPIC seems correct" "$regx"
|
||||
textPass "$regx: SNS topic $SHORT_TOPIC's policy with public access but has a Condition" "$SHORT_TOPIC" "$regx"
|
||||
fi
|
||||
else
|
||||
textPass "$regx: SNS topic without public access" "$SHORT_TOPIC" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No SNS topics found" "$regx"
|
||||
textInfo "$regx: No SNS topic found" "$SHORT_TOPIC" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@ extra733(){
|
||||
textInfo "SAML Provider $PROVIDER_NAME has been found"
|
||||
done
|
||||
else
|
||||
textFail "No SAML Provider found, add one and use STS"
|
||||
textInfo "No SAML Provider found, add one and use STS"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -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 and 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 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra734="NOT_SCORED"
|
||||
CHECK_TYPE_extra734="EXTRA"
|
||||
CHECK_ALTERNATE_check734="extra734"
|
||||
@@ -20,28 +20,54 @@ extra734(){
|
||||
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
|
||||
if [[ $LIST_OF_BUCKETS ]]; then
|
||||
for bucket in $LIST_OF_BUCKETS;do
|
||||
# query to get if has encryption enabled or not
|
||||
RESULT=$(echo $bucket $($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1 | grep -v ServerSideEncryptionConfigurationNotFoundError))
|
||||
TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
|
||||
# get bucket policy
|
||||
$AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null
|
||||
# check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true
|
||||
CHECK_BUCKET_SSE_POLICY=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep \"true\")
|
||||
echo "$RESULT" | while read RBUCKET SSEALG; do
|
||||
if [[ $SSEALG ]]; then
|
||||
if [[ $CHECK_BUCKET_SSE_POLICY ]]; then
|
||||
textPass "Bucket $RBUCKET has SSE enabled with algorithm $SSEALG and S3 policy to enforce it"
|
||||
else
|
||||
# I'll leave it as Pass but to prevent uploads of unencrypted
|
||||
# objects to Amazon S3 a policy to enforce it is required
|
||||
textPass "Bucket $RBUCKET has SSE enabled with algorithm $SSEALG but no S3 enforcing policy found!"
|
||||
fi
|
||||
else
|
||||
textFail "Bucket $RBUCKET has Server Side Encryption disabled!"
|
||||
fi
|
||||
done
|
||||
rm -fr $TEMP_SSE_POLICY_FILE
|
||||
done
|
||||
|
||||
# For this test to pass one of the following must be present:
|
||||
# - Configure ServerSideEncryptionConfiguration rule for AES256 or aws:kms
|
||||
# OR
|
||||
# - Have bucket policy denying s3:PutObject when s3:x-amz-server-side-encryption is absent
|
||||
|
||||
# query to get if has encryption enabled or not
|
||||
RESULT=$($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1)
|
||||
if [[ $(echo "$RESULT" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Encryption for $bucket"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ $RESULT == "AES256" || $RESULT == "aws:kms" ]];
|
||||
then
|
||||
textPass "Bucket $bucket is enabled for default encryption with $RESULT"
|
||||
continue
|
||||
fi
|
||||
|
||||
TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
|
||||
|
||||
# get bucket policy
|
||||
$AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2>&1
|
||||
if [[ $(grep AccessDenied $TEMP_SSE_POLICY_FILE) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Policy for $bucket"
|
||||
rm -f $TEMP_SSE_POLICY_FILE
|
||||
continue
|
||||
fi
|
||||
if [[ $(grep NoSuchBucketPolicy $TEMP_SSE_POLICY_FILE) ]]; then
|
||||
textFail "No bucket policy for $bucket"
|
||||
rm -f $TEMP_SSE_POLICY_FILE
|
||||
continue
|
||||
fi
|
||||
|
||||
# check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true
|
||||
CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and ((.Principal|type == "object") and .Principal.AWS == "*") 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!"
|
||||
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"
|
||||
|
||||
rm -f $TEMP_SSE_POLICY_FILE
|
||||
done
|
||||
|
||||
else
|
||||
textInfo "No S3 Buckets found"
|
||||
fi
|
||||
|
||||
@@ -11,25 +11,26 @@
|
||||
# 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 ELBs have logging enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_TITLE_extra739="[extra739] Check if RDS instances have backup enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra739="NOT_SCORED"
|
||||
CHECK_TYPE_extra739="EXTRA"
|
||||
CHECK_ALTERNATE_check739="extra739"
|
||||
|
||||
extra739(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_ELB=$($AWSCLI elb describe-load-balancers --region $regx $PROFILE_OPT --query LoadBalancerDescriptions[*].LoadBalancerName --output text)
|
||||
if [[ $LIST_OF_ELB ]];then
|
||||
for elb_id in $LIST_OF_ELB; do
|
||||
CHECK_LOG_STATUS=$($AWSCLI elb describe-load-balancer-attributes --region $regx $PROFILE_OPT --load-balancer-name $elb_id --query LoadBalancerAttributes.AccessLog.Enabled --output text|grep False)
|
||||
if [[ $CHECK_LOG_STATUS ]]; then
|
||||
textFail "$regx: ELB $elb_id has login disabled!" "$regx"
|
||||
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
|
||||
# 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"
|
||||
else
|
||||
textPass "$regx: ELB $elb_id has login enabled" "$regx"
|
||||
textPass "$regx: RDS instance $rdsinstance has backup enabled with retention period $BACKUP_RETENTION days " "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No ELBs found" "$regx"
|
||||
textInfo "$regx: No RDS instances found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ extra74(){
|
||||
if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then
|
||||
textFail "$regx: $SG_ID has no ingress filtering and it is being used!" "$regx"
|
||||
else
|
||||
textInfo "$regx: $SG_ID has no ingress filtering but it is no being used" "$regx"
|
||||
textInfo "$regx: $SG_ID has no ingress filtering but it is not being used" "$regx"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
68
checks/check_extra741
Normal file
68
checks/check_extra741
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra741="7.41"
|
||||
CHECK_TITLE_extra741="[extra741] Find secrets in EC2 User Data (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra741="NOT_SCORED"
|
||||
CHECK_TYPE_extra741="EXTRA"
|
||||
CHECK_ALTERNATE_check741="extra741"
|
||||
|
||||
extra741(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
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
|
||||
for instance in $LIST_OF_EC2_INSTANCES; do
|
||||
EC2_USERDATA_FILE="$SECRETS_TEMP_FOLDER/extra741-$instance-userData.decoded"
|
||||
EC2_USERDATA=$($AWSCLI ec2 describe-instance-attribute --attribute userData $PROFILE_OPT --region $regx --instance-id $instance --query UserData.Value --output text| grep -v ^None | decode_report > $EC2_USERDATA_FILE)
|
||||
if [ -s $EC2_USERDATA_FILE ];then
|
||||
FILE_FORMAT_ASCII=$(file -b $EC2_USERDATA_FILE|grep ASCII)
|
||||
# This finds ftp or http URLs with credentials and common keywords
|
||||
# FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $EC2_USERDATA_FILE |wc -l|tr -d '\ ')
|
||||
# New implementation using https://github.com/Yelp/detect-secrets
|
||||
if [[ $FILE_FORMAT_ASCII ]]; then
|
||||
FINDINGS=$(secretsDetector file $EC2_USERDATA_FILE)
|
||||
if [[ $FINDINGS -eq 0 ]]; then
|
||||
textPass "$regx: No secrets found in $instance" "$regx"
|
||||
# delete file if nothing interesting is there
|
||||
rm -f $EC2_USERDATA_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in $instance" "$regx"
|
||||
# delete file to not leave trace, user must look at the instance User Data
|
||||
rm -f $EC2_USERDATA_FILE
|
||||
fi
|
||||
else
|
||||
mv $EC2_USERDATA_FILE $EC2_USERDATA_FILE.gz ; gunzip $EC2_USERDATA_FILE.gz
|
||||
FINDINGS=$(secretsDetector file $EC2_USERDATA_FILE)
|
||||
if [[ $FINDINGS -eq 0 ]]; then
|
||||
textPass "$regx: No secrets found in $instance User Data" "$regx"
|
||||
rm -f $EC2_USERDATA_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in $instance" "$regx"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
textPass "$regx: No secrets found in $instance User Data or it is empty" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No EC2 instances found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
56
checks/check_extra742
Normal file
56
checks/check_extra742
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/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_extra742="7.42"
|
||||
CHECK_TITLE_extra742="[extra742] Find secrets in CloudFormation outputs (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra742="NOT_SCORED"
|
||||
CHECK_TYPE_extra742="EXTRA"
|
||||
CHECK_ALTERNATE_check742="extra742"
|
||||
|
||||
extra742(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
textInfo "Looking for secrets in CloudFormation output across all regions... "
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_CFN_STACKS=$($AWSCLI cloudformation describe-stacks $PROFILE_OPT --region $regx --query Stacks[*].[StackName] --output text)
|
||||
if [[ $LIST_OF_CFN_STACKS ]];then
|
||||
for stack in $LIST_OF_CFN_STACKS; do
|
||||
CFN_OUTPUTS_FILE="$SECRETS_TEMP_FOLDER/extra742-$stack-$regx-outputs.txt"
|
||||
CFN_OUTPUTS=$($AWSCLI $PROFILE_OPT --region $regx cloudformation describe-stacks --query "Stacks[?StackName==\`$stack\`].Outputs[*].[OutputKey,OutputValue]" --output text > $CFN_OUTPUTS_FILE)
|
||||
if [ -s $CFN_OUTPUTS_FILE ];then
|
||||
# This finds ftp or http URLs with credentials and common keywords
|
||||
# FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $CFN_OUTPUTS_FILE |wc -l|tr -d '\ ')
|
||||
# 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"
|
||||
# delete file if nothing interesting is there
|
||||
rm -f $CFN_OUTPUTS_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in stack $stack Outputs" "$regx"
|
||||
# delete file to not leave trace, user must look at the CFN Stack
|
||||
rm -f $CFN_OUTPUTS_FILE
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: CloudFormation stack $stack has no Outputs" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No CloudFormation stacks found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
41
checks/check_extra743
Normal file
41
checks/check_extra743
Normal file
@@ -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_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_SCORED_extra743="NOT_SCORED"
|
||||
CHECK_TYPE_extra743="EXTRA"
|
||||
CHECK_ALTERNATE_check743="extra743"
|
||||
|
||||
extra743(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text)
|
||||
if [[ $LIST_OF_REST_APIS ]];then
|
||||
for api in $LIST_OF_REST_APIS; do
|
||||
API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text)
|
||||
LIST_OF_STAGES=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-stages --rest-api-id $api --query 'item[*].stageName' --output text)
|
||||
if [[ $LIST_OF_STAGES ]]; then
|
||||
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"
|
||||
else
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not client certificate enabled" "$regx"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No API Gateways found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
41
checks/check_extra744
Normal file
41
checks/check_extra744
Normal file
@@ -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_extra744="7.44"
|
||||
CHECK_TITLE_extra744="[extra744] Check if API Gateway has a WAF ACL attached (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra744="NOT_SCORED"
|
||||
CHECK_TYPE_extra744="EXTRA"
|
||||
CHECK_ALTERNATE_check744="extra744"
|
||||
|
||||
extra744(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text)
|
||||
if [[ $LIST_OF_REST_APIS ]];then
|
||||
for api in $LIST_OF_REST_APIS; do
|
||||
API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text)
|
||||
LIST_OF_STAGES=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-stages --rest-api-id $api --query 'item[*].stageName' --output text)
|
||||
if [[ $LIST_OF_STAGES ]]; then
|
||||
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"
|
||||
else
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $api in $stage has not WAF ACL attached" "$regx"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No API Gateways found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
43
checks/check_extra745
Normal file
43
checks/check_extra745
Normal file
@@ -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_extra745="7.45"
|
||||
CHECK_TITLE_extra745="[extra745] Check if API Gateway endpoint is public or private (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra745="NOT_SCORED"
|
||||
CHECK_TYPE_extra745="EXTRA"
|
||||
CHECK_ALTERNATE_check745="extra745"
|
||||
|
||||
extra745(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text)
|
||||
if [[ $LIST_OF_REST_APIS ]];then
|
||||
for api in $LIST_OF_REST_APIS; do
|
||||
API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text)
|
||||
ENDPOINT_CONFIG_TYPE=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-api --rest-api-id $api --query endpointConfiguration.types --output text)
|
||||
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"
|
||||
;;
|
||||
REGIONAL )
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx"
|
||||
;;
|
||||
EDGE )
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $api is internet accesible as $ENDPOINT_CONFIG_TYPE" "$regx"
|
||||
esac
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No API Gateways found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
36
checks/check_extra746
Normal file
36
checks/check_extra746
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/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_extra746="7.46"
|
||||
CHECK_TITLE_extra746="[extra746] Check if API Gateway has configured authorizers (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra746="NOT_SCORED"
|
||||
CHECK_TYPE_extra746="EXTRA"
|
||||
CHECK_ALTERNATE_check746="extra746"
|
||||
|
||||
extra746(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_REST_APIS=$($AWSCLI $PROFILE_OPT --region $regx apigateway get-rest-apis --query 'items[*].id' --output text)
|
||||
if [[ $LIST_OF_REST_APIS ]];then
|
||||
for api in $LIST_OF_REST_APIS; do
|
||||
API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$api\`].name" --output text)
|
||||
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"
|
||||
else
|
||||
textFail "$regx: API Gateway $API_GW_NAME ID $api has not authorizer configured" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No API Gateways found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
36
checks/check_extra747
Normal file
36
checks/check_extra747
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/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_extra747="7.47"
|
||||
CHECK_TITLE_extra747="[extra747] Check if RDS instances is integrated with CloudWatch Logs (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra747="NOT_SCORED"
|
||||
CHECK_TYPE_extra747="EXTRA"
|
||||
CHECK_ALTERNATE_check747="extra747"
|
||||
|
||||
extra747(){
|
||||
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
|
||||
# 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"
|
||||
else
|
||||
textFail "$regx: RDS instance $rdsinstance has not CloudWatch Logs enabled!" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No RDS instances found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra748
Normal file
30
checks/check_extra748
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/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_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_SCORED_extra748="NOT_SCORED"
|
||||
CHECK_TYPE_extra748="EXTRA"
|
||||
CHECK_ALTERNATE_check748="extra748"
|
||||
|
||||
extra748(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort==`0` && ToPort==`65535`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
if [[ $SG_LIST ]];then
|
||||
for SG in $SG_LIST;do
|
||||
textFail "$regx: Found Security Group: $SG open to 0.0.0.0/0" "$regx"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra749
Normal file
30
checks/check_extra749
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/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_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_SCORED_extra749="NOT_SCORED"
|
||||
CHECK_TYPE_extra749="EXTRA"
|
||||
CHECK_ALTERNATE_check749="extra749"
|
||||
|
||||
extra749(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`1521` && ToPort>=`1521`)||(FromPort<=`2483` && ToPort>=`2483`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found with any port open to 0.0.0.0/0 for Oracle ports" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -21,12 +21,25 @@ CHECK_ALTERNATE_check705="extra75"
|
||||
extra75(){
|
||||
# "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)"
|
||||
textInfo "Looking for Security Groups in all regions... "
|
||||
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS)
|
||||
SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --max-items $MAXITEMS | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add')
|
||||
if [[ $SECURITYGROUPS == "null" ]];
|
||||
then
|
||||
continue
|
||||
fi
|
||||
LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUPS|jq -r 'to_entries|sort_by(.key)|.[]|.key')
|
||||
for SG_ID in $LIST_OF_SECURITYGROUPS; do
|
||||
SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text)
|
||||
# Default security groups can not be deleted, so draw attention to them
|
||||
if [[ $SG_NOT_USED -eq 0 ]];then
|
||||
textFail "$regx: $SG_ID is not being used!" "$regx"
|
||||
GROUP_NAME=$(echo $SECURITYGROUPS | jq -r --arg id $SG_ID '.[$id]')
|
||||
if [[ $GROUP_NAME != "default" ]];
|
||||
then
|
||||
textFail "$regx: $SG_ID is not being used!" "$regx"
|
||||
else
|
||||
textInfo "$regx: $SG_ID is not being used - default security group" "$regx"
|
||||
fi
|
||||
else
|
||||
textPass "$regx: $SG_ID is being used" "$regx"
|
||||
fi
|
||||
|
||||
30
checks/check_extra750
Normal file
30
checks/check_extra750
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/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_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_SCORED_extra750="NOT_SCORED"
|
||||
CHECK_TYPE_extra750="EXTRA"
|
||||
CHECK_ALTERNATE_check750="extra750"
|
||||
|
||||
extra750(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3306` && ToPort>=`3306`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for MySQL port" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra751
Normal file
30
checks/check_extra751
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra751="7.51"
|
||||
CHECK_TITLE_extra751="[extra751] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Postgres port 5432 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra751="NOT_SCORED"
|
||||
CHECK_TYPE_extra751="EXTRA"
|
||||
CHECK_ALTERNATE_check751="extra751"
|
||||
|
||||
extra751(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`5432` && ToPort>=`5432`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Postgres port" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra752
Normal file
30
checks/check_extra752
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra752="7.52"
|
||||
CHECK_TITLE_extra752="[extra752] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Redis port 6379 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra752="NOT_SCORED"
|
||||
CHECK_TYPE_extra752="EXTRA"
|
||||
CHECK_ALTERNATE_check752="extra752"
|
||||
|
||||
extra752(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`6379` && ToPort>=`6379`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Redis port" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra753
Normal file
30
checks/check_extra753
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra753="7.53"
|
||||
CHECK_TITLE_extra753="[extra753] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MongoDB ports 27017 and 27018 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra753="NOT_SCORED"
|
||||
CHECK_TYPE_extra753="EXTRA"
|
||||
CHECK_ALTERNATE_check753="extra753"
|
||||
|
||||
extra753(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`27017` && ToPort>=`27017`) || (FromPort<=`27018` && ToPort>=`27018`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for MongoDB ports" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra754
Normal file
30
checks/check_extra754
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra754="7.54"
|
||||
CHECK_TITLE_extra754="[extra754] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Cassandra ports 7199 or 9160 or 8888 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra754="NOT_SCORED"
|
||||
CHECK_TYPE_extra754="EXTRA"
|
||||
CHECK_ALTERNATE_check754="extra754"
|
||||
|
||||
extra754(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || ((FromPort<=`7199` && ToPort>=`7199`) || (FromPort<=`9160` && ToPort>=`9160`)|| (FromPort<=`8888` && ToPort>=`8888`))) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Cassandra ports" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
30
checks/check_extra755
Normal file
30
checks/check_extra755
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra755="7.55"
|
||||
CHECK_TITLE_extra755="[extra755] Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Memcached port 11211 (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra755="NOT_SCORED"
|
||||
CHECK_TYPE_extra755="EXTRA"
|
||||
CHECK_ALTERNATE_check755="extra755"
|
||||
|
||||
extra755(){
|
||||
for regx in $REGIONS; do
|
||||
SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`11211` && ToPort>=`11211`)) && (contains(IpRanges[].CidrIp, `0.0.0.0/0`) || contains(Ipv6Ranges[].CidrIpv6, `::/0`))]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text)
|
||||
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"
|
||||
done
|
||||
else
|
||||
textPass "$regx: No Security Groups found open to 0.0.0.0/0 for Memcached port" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
35
checks/check_extra756
Normal file
35
checks/check_extra756
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/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_ALTERNATE_check756="extra756"
|
||||
|
||||
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
|
||||
}
|
||||
40
checks/check_extra757
Normal file
40
checks/check_extra757
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra757="7.57"
|
||||
CHECK_TITLE_extra757="[extra757] Check EC2 Instances older than 6 months (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra757="NOT_SCORED"
|
||||
CHECK_TYPE_extra757="EXTRA"
|
||||
CHECK_ALTERNATE_check757="extra757"
|
||||
|
||||
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
|
||||
INSTACES_OLD_THAN_AGE=$($AWSCLI ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" $PROFILE_OPT --region $regx --output text)
|
||||
if [[ $INSTACES_OLD_THAN_AGE ]]; then
|
||||
while IFS= read -r ec2_instace
|
||||
do
|
||||
EC2_ID=$(echo "$ec2_instace" | awk '{print $1}')
|
||||
LAUNCH_DATE=$(echo "$ec2_instace" | awk '{print $2}')
|
||||
textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx"
|
||||
done <<< "$INSTACES_OLD_THAN_AGE"
|
||||
else
|
||||
textPass "$regx: All Instances newer than 6 months" "$regx"
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: No EC2 Instances Found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
40
checks/check_extra758
Normal file
40
checks/check_extra758
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra758="7.58"
|
||||
CHECK_TITLE_extra758="[extra758] Check EC2 Instances older than 12 months (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra758="NOT_SCORED"
|
||||
CHECK_TYPE_extra758="EXTRA"
|
||||
CHECK_ALTERNATE_check758="extra758"
|
||||
|
||||
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
|
||||
INSTACES_OLD_THAN_AGE=$($AWSCLI ec2 describe-instances --query "Reservations[].Instances[?LaunchTime<='$OLDAGE'][].{id: InstanceId, launched: LaunchTime}" $PROFILE_OPT --region $regx --output text)
|
||||
if [[ $INSTACES_OLD_THAN_AGE ]]; then
|
||||
while IFS= read -r ec2_instace
|
||||
do
|
||||
EC2_ID=$(echo "$ec2_instace" | awk '{print $1}')
|
||||
LAUNCH_DATE=$(echo "$ec2_instace" | awk '{print $2}')
|
||||
textFail "$regx: EC2 Instance $EC2_ID running before than $OLDAGE" "$regx"
|
||||
done <<< "$INSTACES_OLD_THAN_AGE"
|
||||
else
|
||||
textPass "$regx: All Instances newer than 12 months" "$regx"
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: No EC2 Instances Found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
54
checks/check_extra759
Normal file
54
checks/check_extra759
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/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_extra759="7.59"
|
||||
CHECK_TITLE_extra759="[extra759] Find secrets in Lambda functions variables (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra759="NOT_SCORED"
|
||||
CHECK_TYPE_extra759="EXTRA"
|
||||
CHECK_ALTERNATE_check759="extra759"
|
||||
|
||||
extra759(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
textInfo "Looking for secrets in 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
|
||||
for lambdafunction in $LIST_OF_FUNCTIONS;do
|
||||
LAMBDA_FUNCTION_VARIABLES_FILE="$SECRETS_TEMP_FOLDER/extra759-$lambdafunction-$regx-variables.txt"
|
||||
LAMBDA_FUNCTION_VARIABLES=$($AWSCLI lambda $PROFILE_OPT --region $regx get-function-configuration --function-name $lambdafunction --query 'Environment.Variables' --output text > $LAMBDA_FUNCTION_VARIABLES_FILE)
|
||||
if [ -s $LAMBDA_FUNCTION_VARIABLES_FILE ];then
|
||||
# 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"
|
||||
# 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"
|
||||
# delete file to not leave trace, user must look at the function
|
||||
rm -f $LAMBDA_FUNCTION_VARIABLES_FILE
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: Lambda function $stalambdafunction has not variables" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No Lambda functions found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
55
checks/check_extra760
Normal file
55
checks/check_extra760
Normal file
@@ -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_extra760="7.60"
|
||||
CHECK_TITLE_extra760="[extra760] Find secrets in Lambda functions code (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra760="NOT_SCORED"
|
||||
CHECK_TYPE_extra760="EXTRA"
|
||||
CHECK_ALTERNATE_check760="extra760"
|
||||
|
||||
extra760(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
textInfo "Looking for secrets in 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
|
||||
for lambdafunction in $LIST_OF_FUNCTIONS;do
|
||||
LAMBDA_FUNCTION_FOLDER="$SECRETS_TEMP_FOLDER/extra760-$lambdafunction-$regx"
|
||||
LAMBDA_FUNCTION_FILE="$lambdafunction-code.zip"
|
||||
LAMBDA_CODE_LOCATION=$($AWSCLI lambda get-function $PROFILE_OPT --region $regx --function-name $lambdafunction --query Code.Location --output text)
|
||||
mkdir $LAMBDA_FUNCTION_FOLDER
|
||||
# DOWNLOAD the code in a zip file
|
||||
curl -s $LAMBDA_CODE_LOCATION -o $LAMBDA_FUNCTION_FOLDER/$LAMBDA_FUNCTION_FILE
|
||||
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"
|
||||
# delete files if nothing interesting is there
|
||||
rm -fr $LAMBDA_FUNCTION_FOLDER
|
||||
else
|
||||
textFail "$regx: Potential secret found in Lambda function $lambdafunction code" "$regx"
|
||||
# delete files to not leave trace, user must look at the function
|
||||
rm -fr $LAMBDA_FUNCTION_FOLDER
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No Lambda functions found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -fr $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
37
checks/check_extra761
Normal file
37
checks/check_extra761
Normal file
@@ -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_extra761="7.61"
|
||||
CHECK_TITLE_extra761="[extra761] Check if EBS Default Encryption is activated (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra761="NOT_SCORED"
|
||||
CHECK_TYPE_extra761="EXTRA"
|
||||
CHECK_ALTERNATE_check761="extra761"
|
||||
|
||||
extra761(){
|
||||
textInfo "Looking for EBS Default Encryption activation in all regions... "
|
||||
for regx in $REGIONS; do
|
||||
EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault' 2>&1)
|
||||
if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep "argument operation: Invalid choice") ]]; then
|
||||
textFail "Newer aws cli needed for get-ebs-encryption-by-default"
|
||||
continue
|
||||
fi
|
||||
if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then
|
||||
textFail "Prowler needs ec2:GetEbsEncryptionByDefault permission for this check"
|
||||
continue
|
||||
fi
|
||||
if [[ $EBS_DEFAULT_ENCRYPTION == "true" ]];then
|
||||
textPass "$regx: EBS Default Encryption is activated" "$regx"
|
||||
else
|
||||
textFail "$regx: EBS Default Encryption is not activated" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
41
checks/check_extra762
Normal file
41
checks/check_extra762
Normal file
@@ -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_extra762="7.62"
|
||||
CHECK_TITLE_extra762="[extra762] Find obsolete Lambda runtimes (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra762="NOT_SCORED"
|
||||
CHECK_TYPE_extra762="EXTRA"
|
||||
CHECK_ALTERNATE_check762="extra762"
|
||||
|
||||
extra762(){
|
||||
|
||||
# regex to match OBSOLETE runtimes in string functionName%runtime
|
||||
# https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html
|
||||
OBSOLETE='%(nodejs4.3|nodejs4.3-edge|nodejs6.10|nodejs8.10|dotnetcore1.0|dotnetcore2.0)'
|
||||
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --output text --query 'Functions[*].{R:Runtime,N:FunctionName}' | tr "\t" "%")
|
||||
if [[ $LIST_OF_FUNCTIONS ]]; then
|
||||
for lambdafunction in $LIST_OF_FUNCTIONS;do
|
||||
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"
|
||||
else
|
||||
textPass "$regx: Supported runtime: ${runtime} used by: ${fname}" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No Lambda functions found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
38
checks/check_extra763
Normal file
38
checks/check_extra763
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/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_extra763="7.63"
|
||||
CHECK_TITLE_extra763="[extra763] Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra763="NOT_SCORED"
|
||||
CHECK_TYPE_extra763="EXTRA"
|
||||
CHECK_ALTERNATE_check763="extra763"
|
||||
|
||||
extra763(){
|
||||
# "Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
|
||||
if [[ $LIST_OF_BUCKETS ]]; then
|
||||
for bucket in $LIST_OF_BUCKETS;do
|
||||
BUCKET_VERSIONING_ENABLED=$($AWSCLI s3api get-bucket-versioning --bucket $bucket $PROFILE_OPT --query Status --output text 2>&1)
|
||||
if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Versioning for $bucket"
|
||||
continue
|
||||
fi
|
||||
if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then
|
||||
textPass "Bucket $bucket has versioning enabled"
|
||||
else
|
||||
textFail "Bucket $bucket has versioning disabled!"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "No S3 Buckets found"
|
||||
fi
|
||||
}
|
||||
52
checks/check_extra764
Normal file
52
checks/check_extra764
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra764="7.64"
|
||||
CHECK_TITLE_extra764="[extra764] Check if S3 buckets have secure transport policy (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra764="NOT_SCORED"
|
||||
CHECK_TYPE_extra764="EXTRA"
|
||||
CHECK_ALTERNATE_check764="extra764"
|
||||
|
||||
extra764(){
|
||||
LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1)
|
||||
if [[ $LIST_OF_BUCKETS ]]; then
|
||||
for bucket in $LIST_OF_BUCKETS;do
|
||||
TEMP_STP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX)
|
||||
|
||||
# get bucket policy
|
||||
$AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_STP_POLICY_FILE 2>&1
|
||||
if [[ $(grep AccessDenied $TEMP_STP_POLICY_FILE) ]]; then
|
||||
textFail "Access Denied Trying to Get Bucket Policy for $bucket"
|
||||
rm -f $TEMP_STP_POLICY_FILE
|
||||
continue
|
||||
fi
|
||||
if [[ $(grep NoSuchBucketPolicy $TEMP_STP_POLICY_FILE) ]]; then
|
||||
textFail "No bucket policy for $bucket"
|
||||
rm -f $TEMP_STP_POLICY_FILE
|
||||
continue
|
||||
fi
|
||||
|
||||
# https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-policy-for-config-rule/
|
||||
CHECK_BUCKET_STP_POLICY_PRESENT=$(cat $TEMP_STP_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}" '.Statement[]|select((((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and .Action=="s3:*" 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"
|
||||
else
|
||||
textFail "Bucket $bucket allows requests over insecure transport"
|
||||
fi
|
||||
|
||||
rm -fr $TEMP_STP_POLICY_FILE
|
||||
done
|
||||
|
||||
else
|
||||
textInfo "No S3 Buckets found"
|
||||
fi
|
||||
}
|
||||
58
checks/check_extra765
Normal file
58
checks/check_extra765
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
# Remediation:
|
||||
#
|
||||
# https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html
|
||||
#
|
||||
# aws ecr put-image-scanning-configuration \
|
||||
# --region <value> \
|
||||
# --repository-name <value> \
|
||||
# --image-scanning-configuration scanOnPush=true
|
||||
|
||||
CHECK_ID_extra765="7.65"
|
||||
CHECK_TITLE_extra765="[extra765] Check if ECR image scan on push is enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra765="NOT_SCORED"
|
||||
CHECK_TYPE_extra765="EXTRA"
|
||||
CHECK_ALTERNATE_check765="extra765"
|
||||
|
||||
extra765(){
|
||||
for region in $REGIONS; do
|
||||
LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[*].[repositoryName]" --output text 2>&1)
|
||||
if [[ $(echo "$LIST_ECR_REPOS" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to describe ECR repositories"
|
||||
continue
|
||||
fi
|
||||
if [[ ! -z "$LIST_ECR_REPOS" ]]; then
|
||||
for repo in $LIST_ECR_REPOS; do
|
||||
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"
|
||||
;;
|
||||
"False")
|
||||
textFail "$region: ECR repository $repo has scan on push disabled!" "$region"
|
||||
;;
|
||||
"None")
|
||||
textInfo "$region: ECR repository $repo hs no scanOnPush status, newer awscli needed" "$region"
|
||||
;;
|
||||
"*")
|
||||
textInfo "$region: ECR repository $repo has unknown scanOnPush status \"$SCAN_ENABLED\"" "$region"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
textInfo "$region: No ECR repositories found" "$region"
|
||||
fi
|
||||
done
|
||||
}
|
||||
33
checks/check_extra767
Normal file
33
checks/check_extra767
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra767="7.67"
|
||||
CHECK_TITLE_extra767="[extra767] Check if CloudFront distributions have Field Level Encryption enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra767="NOT_SCORED"
|
||||
CHECK_TYPE_extra767="EXTRA"
|
||||
CHECK_ALTERNATE_check767="extra767"
|
||||
|
||||
extra767(){
|
||||
LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions --query 'DistributionList.Items[*].Id' $PROFILE_OPT --output text|grep -v ^None)
|
||||
if [[ $LIST_OF_DISTRIBUTIONS ]];then
|
||||
for dist in $LIST_OF_DISTRIBUTIONS; do
|
||||
CHECK_FLE=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.DefaultCacheBehavior.FieldLevelEncryptionId $PROFILE_OPT --output text)
|
||||
if [[ $CHECK_FLE ]]; then
|
||||
textPass "CloudFront distribution $dist has Field Level Encryption enabled" "$regx"
|
||||
else
|
||||
textFail "CloudFront distribution $dist has Field Level Encryption disabled!" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "No CloudFront distributions found" "$regx"
|
||||
fi
|
||||
}
|
||||
55
checks/check_extra768
Normal file
55
checks/check_extra768
Normal file
@@ -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_extra768="7.68"
|
||||
CHECK_TITLE_extra768="[extra768] Find secrets in ECS task definitions variables (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra768="NOT_SCORED"
|
||||
CHECK_TYPE_extra768="EXTRA"
|
||||
CHECK_ALTERNATE_check768="extra768"
|
||||
|
||||
extra768(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
textInfo "Looking for secrets in ECS task definitions' environment variables across all regions... "
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_TASK_DEFINITIONS=$($AWSCLI ecs list-task-definitions $PROFILE_OPT --region $regx --query taskDefinitionArns[*] --output text)
|
||||
if [[ $LIST_OF_TASK_DEFINITIONS ]]; then
|
||||
for taskDefinition in $LIST_OF_TASK_DEFINITIONS;do
|
||||
IFS='/' read -r -a splitArn <<< "$taskDefinition"
|
||||
TASK_DEFINITION=${splitArn[1]}
|
||||
TASK_DEFINITION_ENV_VARIABLES_FILE="$SECRETS_TEMP_FOLDER/extra768-$TASK_DEFINITION-$regx-variables.txt"
|
||||
TASK_DEFINITION_ENV_VARIABLES=$($AWSCLI ecs $PROFILE_OPT --region $regx describe-task-definition --task-definition $taskDefinition --query 'taskDefinition.containerDefinitions[*].environment' --output text > $TASK_DEFINITION_ENV_VARIABLES_FILE)
|
||||
if [ -s $TASK_DEFINITION_ENV_VARIABLES_FILE ];then
|
||||
# Implementation using https://github.com/Yelp/detect-secrets
|
||||
FINDINGS=$(secretsDetector file $TASK_DEFINITION_ENV_VARIABLES_FILE)
|
||||
if [[ $FINDINGS -eq 0 ]]; then
|
||||
textPass "$regx: No secrets found in ECS task definition $TASK_DEFINITION variables" "$regx"
|
||||
# delete file if nothing interesting is there
|
||||
rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in ECS task definition $TASK_DEFINITION variables" "$regx"
|
||||
fi
|
||||
else
|
||||
textInfo "$regx: ECS task definition $TASK_DEFINITION has no variables" "$regx"
|
||||
rm -f $TASK_DEFINITION_ENV_VARIABLES_FILE
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No ECS task definitions found" "$regx"
|
||||
fi
|
||||
done
|
||||
# rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
44
checks/check_extra769
Normal file
44
checks/check_extra769
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/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_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_SCORED_extra769="NOT_SCORED"
|
||||
CHECK_TYPE_extra769="EXTRA"
|
||||
CHECK_ALTERNATE_check769="extra769"
|
||||
|
||||
extra769(){
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_ACCESS_ANALYZERS=$($AWSCLI accessanalyzer list-analyzers $PROFILE_OPT --region $regx --query analyzers[*].arn --output text 2>&1)
|
||||
if [[ $(echo "$LIST_OF_ACCESS_ANALYZERS" | grep -i "argument command: Invalid choice") ]]; then
|
||||
textInfo "$regx: list-analyzers not supported, newer awscli needed" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $(echo "$LIST_OF_ACCESS_ANALYZERS" | grep -i "AccessDeniedException") ]]; then
|
||||
textFail "$regx: Access Denied trying to list-analyzers" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_OF_ACCESS_ANALYZERS ]]; then
|
||||
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"
|
||||
else
|
||||
textInfo "$regx: IAM Access Analyzer $accessAnalyzerArn has $ANALYZER_ACTIVE_FINDINGS_COUNT active findings" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No IAM Access Analyzers found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
# 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_extra77="7.7,7.07"
|
||||
CHECK_TITLE_extra77="[extra77] Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra77="NOT_SCORED"
|
||||
@@ -20,20 +21,38 @@ CHECK_ALTERNATE_check707="extra77"
|
||||
|
||||
extra77(){
|
||||
# "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)"
|
||||
textInfo "Looking for ECR repos in all regions... "
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query 'repositories[*].{Name:repositoryName}' --output text)
|
||||
for ecr_repo in $LIST_OF_ECR_REPOS; do
|
||||
TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX)
|
||||
$AWSCLI ecr get-repository-policy --repository-name $ecr_repo $PROFILE_OPT --region $regx --output text > $TEMP_POLICY_FILE 2> /dev/null
|
||||
# check if the policy has Principal as *
|
||||
CHECK_ECR_REPO_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*)
|
||||
if [[ $CHECK_ECR_REPO_ALLUSERS_POLICY ]];then
|
||||
textFail "$regx: $ecr_repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx"
|
||||
else
|
||||
textPass "$regx: $ecr_repo is not open" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -fr $TEMP_POLICY_FILE
|
||||
for region in $REGIONS; do
|
||||
LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[*].[repositoryName]" --output text 2>&1)
|
||||
if [[ $(echo "$LIST_ECR_REPOS" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied Trying to describe ECR repositories"
|
||||
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
|
||||
if [[ $(grep AccessDenied $TEMP_POLICY_FILE) ]]; then
|
||||
textFail "$region: $repo Access Denied for get-repository-policy"
|
||||
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"
|
||||
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"
|
||||
else
|
||||
textPass "$region: $repo is not open" "$region"
|
||||
fi
|
||||
rm -f $TEMP_POLICY_FILE
|
||||
done
|
||||
else
|
||||
textInfo "$region: No ECR repositories found" "$region"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
35
checks/check_extra770
Normal file
35
checks/check_extra770
Normal file
@@ -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_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_SCORED_extra770="NOT_SCORED"
|
||||
CHECK_TYPE_extra770="EXTRA"
|
||||
CHECK_ALTERNATE_check770="extra770"
|
||||
|
||||
extra770(){
|
||||
# "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)"
|
||||
textInfo "Looking for instances in all regions... "
|
||||
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
|
||||
while read -r instance;do
|
||||
INSTANCE_ID=$(echo $instance | awk '{ print $1; }')
|
||||
PUBLIC_IP=$(echo $instance | awk '{ print $2; }')
|
||||
INSTANCE_PROFILE=$(echo $instance | awk '{ print $3; }')
|
||||
textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing with Instance Profile $INSTANCE_PROFILE" "$regx"
|
||||
done <<< "$LIST_OF_PUBLIC_INSTANCES_WITH_INSTANCE_PROFILES"
|
||||
else
|
||||
textPass "$regx: no Internet Facing EC2 Instances with Instance Profiles found" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
39
checks/check_extra771
Normal file
39
checks/check_extra771
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/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_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_SCORED_extra771="NOT_SCORED"
|
||||
CHECK_TYPE_extra771="EXTRA"
|
||||
CHECK_ALTERNATE_check771="extra771"
|
||||
|
||||
extra771(){
|
||||
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_POLICY_STATEMENTS=$($AWSCLI s3api $PROFILE_OPT get-bucket-policy --bucket $bucket --output json --query Policy 2>&1)
|
||||
if [[ $BUCKET_POLICY_STATEMENTS == *GetBucketPolicy* ]]; then
|
||||
textInfo "Bucket policy does not exist for bucket $bucket"
|
||||
else
|
||||
BUCKET_POLICY_BAD_STATEMENTS=$(echo $BUCKET_POLICY_STATEMENTS | jq --arg arn "arn:aws: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"
|
||||
else
|
||||
textPass "Bucket $bucket has S3 bucket policy which does not allow public write access"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
textInfo "No S3 Buckets found"
|
||||
fi
|
||||
}
|
||||
36
checks/check_extra772
Normal file
36
checks/check_extra772
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
CHECK_ID_extra772="7.72"
|
||||
CHECK_TITLE_extra772="[extra772] Check if elastic IPs are unused (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra772="NOT_SCORED"
|
||||
CHECK_TYPE_extra772="EXTRA"
|
||||
CHECK_ALTERNATE_check772="extra772"
|
||||
|
||||
extra772(){
|
||||
for region in $REGIONS; do
|
||||
EIP_DUMP=$($AWSCLI ec2 describe-addresses ${PROFILE_OPT} --region $region)
|
||||
EIP_LIST=$(echo $EIP_DUMP | jq -r '.Addresses[].AllocationId')
|
||||
if [[ $EIP_LIST ]]; then
|
||||
for eip in $EIP_LIST; do
|
||||
ASSOCIATION_ID=$(echo $EIP_DUMP | jq -r --arg i "$eip" '.Addresses[]|select(.AllocationId==$i)|.AssociationId')
|
||||
if [[ "$ASSOCIATION_ID" == "null" ]]; then
|
||||
textFail "$region: EIP $eip is unused" $region
|
||||
else
|
||||
textPass "$region: EIP $eip is used" $region
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$region: No Elastic IPs found" $region
|
||||
fi
|
||||
done
|
||||
}
|
||||
34
checks/check_extra773
Normal file
34
checks/check_extra773
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/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_extra773="7.73"
|
||||
CHECK_TITLE_extra773="[extra773] Check if CloudFront distributions are using WAF (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra773="NOT_SCORED"
|
||||
CHECK_TYPE_extra773="EXTRA"
|
||||
CHECK_ALTERNATE_check773="extra773"
|
||||
|
||||
extra773(){
|
||||
# "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
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"
|
||||
else
|
||||
textFail "CloudFront distribution $dist is not using AWS WAF web ACL"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "No CloudFront distributions found"
|
||||
fi
|
||||
}
|
||||
34
checks/check_extra774
Normal file
34
checks/check_extra774
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/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_extra774="1.23"
|
||||
CHECK_TITLE_extra774="[extra774] Check if user have unused console login"
|
||||
CHECK_SCORED_extra774="NOT_SCORED"
|
||||
CHECK_TYPE_extra774="EXTRA"
|
||||
CHECK_ALTERNATE_check774="extra774"
|
||||
|
||||
extra774(){
|
||||
MAX_DAYS=-30
|
||||
LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4,$5 }' |grep true | awk '{ print $1 }')
|
||||
|
||||
for i in $LIST_USERS_WITH_PASSWORD_ENABLED; do
|
||||
user=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep "^$i " |awk '{ print $1 }')
|
||||
last_login_date=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep "^$i " |awk '{ print $2 }')
|
||||
|
||||
days_not_in_use=$(how_many_days_from_today ${last_login_date%T*})
|
||||
if [ "$days_not_in_use" -lt "$MAX_DAYS" ];then
|
||||
textFail "User $user has not used console login for more then ${MAX_DAYS#-} days"
|
||||
else
|
||||
textPass "User $user has used console login in the past ${MAX_DAYS#-} days"
|
||||
fi
|
||||
done
|
||||
}
|
||||
68
checks/check_extra775
Normal file
68
checks/check_extra775
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/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_extra775="0.00"
|
||||
CHECK_TITLE_extra775="[extra775] Find secrets in EC2 Auto Scaling Launch Configuration (Not Scored) (Not part of CIS benchmark)"
|
||||
CHECK_SCORED_extra775="NOT_SCORED"
|
||||
CHECK_TYPE_extra775="EXTRA"
|
||||
CHECK_ALTERNATE_check000="extra775"
|
||||
|
||||
extra775(){
|
||||
SECRETS_TEMP_FOLDER="$PROWLER_DIR/secrets-$ACCOUNT_NUM"
|
||||
if [[ ! -d $SECRETS_TEMP_FOLDER ]]; then
|
||||
# this folder is deleted once this check is finished
|
||||
mkdir $SECRETS_TEMP_FOLDER
|
||||
fi
|
||||
|
||||
textInfo "Looking for secrets in 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
|
||||
for autoscaling_configuration in $LIST_OF_EC2_AUTOSCALING; do
|
||||
EC2_AUTOSCALING_USERDATA_FILE="$SECRETS_TEMP_FOLDER/extra775-$autoscaling_configuration-userData.decoded"
|
||||
EC2_AUTOSCALING_USERDATA=$($AWSCLI autoscaling describe-launch-configurations $PROFILE_OPT --launch-configuration-names $autoscaling_configuration --region $regx --query LaunchConfigurations[*].UserData --output text| grep -v ^None | decode_report > $EC2_AUTOSCALING_USERDATA_FILE)
|
||||
if [ -s $EC2_AUTOSCALING_USERDATA_FILE ];then
|
||||
FILE_FORMAT_ASCII=$(file -b $EC2_AUTOSCALING_USERDATA_FILE | grep ASCII)
|
||||
# This finds ftp or http URLs with credentials and common keywords
|
||||
# FINDINGS=$(egrep -i '[[:alpha:]]*://[[:alnum:]]*:[[:alnum:]]*@.*/|key|secret|token|pass' $EC2_AUTOSCALING_USERDATA_FILE |wc -l|tr -d '\ ')
|
||||
# New implementation using https://github.com/Yelp/detect-secrets
|
||||
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"
|
||||
# delete file if nothing interesting is there
|
||||
rm -f $EC2_AUTOSCALING_USERDATA_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx"
|
||||
# delete file to not leave trace, user must look at the autoscaling_configuration User Data
|
||||
rm -f $EC2_AUTOSCALING_USERDATA_FILE
|
||||
fi
|
||||
else
|
||||
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"
|
||||
rm -f $EC2_AUTOSCALING_USERDATA_FILE
|
||||
else
|
||||
textFail "$regx: Potential secret found in $autoscaling_configuration" "$regx"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
textPass "$regx: No secrets found in $autoscaling_configuration User Data or it is empty" "$regx"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "$regx: No EC2 autoscaling_configurations found" "$regx"
|
||||
fi
|
||||
done
|
||||
rm -rf $SECRETS_TEMP_FOLDER
|
||||
}
|
||||
@@ -22,7 +22,7 @@ extra78(){
|
||||
# "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)"
|
||||
textInfo "Looking for RDS instances in all regions... "
|
||||
for regx in $REGIONS; do
|
||||
LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' --output text)
|
||||
LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true` && DBInstanceStatus=="available"].[DBInstanceIdentifier,Endpoint.Address]' --output text)
|
||||
if [[ $LIST_OF_RDS_PUBLIC_INSTANCES ]];then
|
||||
while read -r rds_instance;do
|
||||
RDS_NAME=$(echo $rds_instance | awk '{ print $1; }')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
||||
# 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
|
||||
@@ -11,6 +11,19 @@
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
# Remediation:
|
||||
#
|
||||
# here URL to the relevand/official documentation
|
||||
#
|
||||
# here commands or steps to fix it if avalable, like:
|
||||
# aws logs put-metric-filter \
|
||||
# --region us-east-1 \
|
||||
# --log-group-name CloudTrail/MyCloudTrailLG \
|
||||
# --filter-name AWSCloudTrailChanges \
|
||||
# --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' \
|
||||
# --metric-transformations metricName=CloudTrailEventCount,metricNamespace=CloudTrailMetrics,metricValue=1
|
||||
|
||||
|
||||
# CHECK_ID_checkN="N.N"
|
||||
# CHECK_TITLE_checkN="[checkN] Description (Not Scored) (Not part of CIS benchmark)"
|
||||
# CHECK_SCORED_checkN="NOT_SCORED"
|
||||
|
||||
@@ -15,7 +15,7 @@ GROUP_ID[10]='hipaa'
|
||||
GROUP_NUMBER[10]='10.0'
|
||||
GROUP_TITLE[10]='HIPAA Compliance - ONLY AS REFERENCE - [hipaa] ****************'
|
||||
GROUP_RUN_BY_DEFAULT[10]='N' # run it when execute_all is called
|
||||
GROUP_CHECKS[10]='check12,check113,check23,check26,check27,check29,extra718,extra725,extra72,extra75,extra739,extra729,extra734,check38,extra73,extra740,extra735'
|
||||
GROUP_CHECKS[10]='check12,check113,check23,check26,check27,check29,extra718,extra725,extra72,extra75,extra717,extra729,extra734,check38,extra73,extra740,extra735'
|
||||
|
||||
# Resources:
|
||||
# https://d0.awsstatic.com/whitepapers/compliance/AWS_HIPAA_Compliance_Whitepaper.pdf
|
||||
|
||||
27
groups/group11_secrets
Normal file
27
groups/group11_secrets
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/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.
|
||||
|
||||
GROUP_ID[11]='secrets'
|
||||
GROUP_NUMBER[11]='11.0'
|
||||
GROUP_TITLE[11]='Look for keys secrets or passwords around resources - [secrets] **'
|
||||
GROUP_RUN_BY_DEFAULT[11]='N' # but it runs when execute_all is called (default)
|
||||
GROUP_CHECKS[11]='extra741,extra742,extra759,extra760,extra768,extra775'
|
||||
|
||||
# requires https://github.com/Yelp/detect-secrets
|
||||
# `pip install detect-secrets`
|
||||
|
||||
# Initially:
|
||||
# - EC2 UserData
|
||||
# - CloudFormation Outputs
|
||||
# - Lambda variables
|
||||
# - Lambda code
|
||||
19
groups/group12_apigateway
Normal file
19
groups/group12_apigateway
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/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.
|
||||
|
||||
GROUP_ID[12]='apigateway'
|
||||
GROUP_NUMBER[12]='12.0'
|
||||
GROUP_TITLE[12]='API Gateway security checks - [apigateway] ********************'
|
||||
GROUP_RUN_BY_DEFAULT[12]='N' # run it when execute_all is called
|
||||
GROUP_CHECKS[12]='extra722,extra743,extra744,extra745,extra746'
|
||||
|
||||
18
groups/group13_rds
Normal file
18
groups/group13_rds
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
GROUP_ID[13]='rds'
|
||||
GROUP_NUMBER[13]='13.0'
|
||||
GROUP_TITLE[13]='RDS security checks - [rds] ***********************************'
|
||||
GROUP_RUN_BY_DEFAULT[13]='N' # run it when execute_all is called
|
||||
GROUP_CHECKS[13]='extra78,extra723,extra735,extra739,extra747'
|
||||
@@ -12,4 +12,4 @@ GROUP_ID[1]='group1'
|
||||
GROUP_NUMBER[1]='1.0'
|
||||
GROUP_TITLE[1]='Identity and Access Management - [group1] **********************'
|
||||
GROUP_RUN_BY_DEFAULT[1]='Y' # run it when execute_all is called
|
||||
GROUP_CHECKS[1]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122'
|
||||
GROUP_CHECKS[1]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,extra774'
|
||||
|
||||
@@ -15,4 +15,7 @@ GROUP_ID[7]='extras'
|
||||
GROUP_NUMBER[7]='7.0'
|
||||
GROUP_TITLE[7]='Extras - [extras] **********************************************'
|
||||
GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called
|
||||
GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740'
|
||||
GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775'
|
||||
|
||||
# Extras 759 and 760 (lambda variables and code secrets finder are not included)
|
||||
# to run detect-secrets use `./prowler -g secrets`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user