Compare commits

...
Author SHA1 Message Date
Jonny 58c85438d3 chore(awslambda): update obsolete lambda runtimes (#7330)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
(cherry picked from commit 9923def4cb)

# Conflicts:
#	prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.py
2025-03-24 10:21:58 +00:00
dependabot[bot] 2fc5b069c5 chore(deps): bump google-api-python-client from 2.162.0 to 2.164.0 (#7267)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 09:38:32 +01:00
dependabot[bot] ef00efa018 chore(deps): bump trufflesecurity/trufflehog from 3.88.17 to 3.88.18 (#7303)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 09:36:07 +01:00
Prowler BotandDaniel Barranquero 3078f10596 fix(route53): solve false positive in route53_public_hosted_zones_cloudwatch_logging_enabled (#7292)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-03-19 13:39:43 +05:45
dependabot[bot] 566205085d chore(deps): bump slack-sdk from 3.34.0 to 3.35.0 (#7261)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 13:03:39 +05:45
dependabot[bot] 9fa419afb6 chore(deps): bump trufflesecurity/trufflehog from 3.88.16 to 3.88.17 (#7278)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 13:03:02 +05:45
dependabot[bot] af0d901038 chore(deps): bump tj-actions/changed-files from 45 to 46 (#7279)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-18 13:02:51 +05:45
926ea897e8 chore(deps): bump microsoft-kiota-abstractions from 1.7.0 to 1.9.2 (#6859)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-03-17 18:33:50 +01:00
dependabot[bot] 9bbd9dbf8b chore(deps): bump azure-identity from 1.19.0 to 1.20.0 (#6963)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 13:53:52 +01:00
dependabot[bot] e1daaded67 chore(deps): bump azure-mgmt-containerservice from 34.0.0 to 34.1.0 (#7029)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 11:17:21 +01:00
Prowler BotandPedro Martín 66060ea68e fix(ens): remove and change duplicated ids (#7179)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-03-11 12:43:10 +01:00
dependabot[bot] 5c97cfcc60 chore(deps): bump trufflesecurity/trufflehog from 3.88.14 to 3.88.16 (#7175)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-11 11:16:33 +01:00
Prowler BotandGary Mclean 4b00aac812 fix(azure): correct check title for SQL Server Unrestricted (#7159)
Co-authored-by: Gary Mclean <gary.mclean@krrv.io>
2025-03-07 19:17:28 +01:00
dependabot[bot] e0f412521b chore(deps-dev): bump mock from 5.1.0 to 5.2.0 (#7105)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 18:24:54 +01:00
Prowler Botandryan-stavella 48bbd7fc79 fix(metadata): typo in ec2_securitygroup_allow_wide_open_public_ipv4 (#7157)
Co-authored-by: ryan-stavella <71134114+ryan-stavella@users.noreply.github.com>
2025-03-07 16:19:02 +01:00
Prowler BotandAndoni Alonso 8a98a12eaa fix(metadata): match type with check results (#7154)
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
2025-03-07 15:28:41 +01:00
Prowler BotandKay Agahd 7b55e465b6 fix(aws): ecs_task_definitions_no_environment_secrets.metadata.json (#7152)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-03-07 15:28:23 +01:00
dependabot[bot] 7d9ebbccd0 chore(deps): bump google-api-python-client from 2.161.0 to 2.162.0 (#7101)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-07 14:31:33 +01:00
dependabot[bot] 0f70295e37 chore(deps-dev): bump mkdocs-material from 9.6.5 to 9.6.7 (#7103)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-04 09:15:36 +01:00
dependabot[bot] b8956ebe37 chore(deps): bump trufflesecurity/trufflehog from 3.88.13 to 3.88.14 (#7095)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-04 09:15:14 +01:00
Prowler BotandDaniel Barranquero 55ef498b1a fix(elasticache): improve logic in elasticache_redis_cluster_backup_enabled (#7044)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-26 11:21:32 +01:00
Prowler BotandHugo Pereira Brito b206e011a9 chore(iam): enhance iam_role_cross_service_confused_deputy_prevention recommendation (#7040)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-26 08:34:27 +01:00
dependabot[bot] 287057e360 chore(deps-dev): bump mkdocs-material from 9.6.4 to 9.6.5 (#7028)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-26 07:50:58 +01:00
dependabot[bot] 21c679fa8e chore(deps): bump kubernetes from 32.0.0 to 32.0.1 (#7031)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 14:33:44 +05:45
dependabot[bot] 6139196c34 chore(deps): bump trufflesecurity/trufflehog from 3.88.9 to 3.88.13 (#7032)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 14:18:27 +05:45
dependabot[bot] ef03ffa4e1 chore(deps): bump python from 3.12.8-alpine3.20 to 3.12.9-alpine3.20 (#6884)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 21:12:10 +05:30
dependabot[bot] e22aef93e6 chore(deps): bump tzlocal from 5.2 to 5.3 (#6959)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 16:36:27 +05:30
dependabot[bot] 974196bec8 chore(deps-dev): bump bandit from 1.8.2 to 1.8.3 (#6961)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 12:18:48 +05:30
dependabot[bot] 0c8c85c526 chore(deps-dev): bump coverage from 7.6.11 to 7.6.12 (#6960)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 11:04:43 +05:30
dependabot[bot] 3c588fed81 chore(deps-dev): bump flake8 from 7.1.1 to 7.1.2 (#6958) 2025-02-19 11:08:22 +01:00
Prowler BotandHugo Pereira Brito 8a3c0fe609 test(cloudfront): add name retrieval test for cloudfront bucket domains (#6974)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-19 09:05:16 +05:30
Prowler BotandHugo Pereira Brito 40e988e109 fix(cloudfront): Incorrect bucket name retrievement (#6950)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-19 08:10:26 +05:30
dependabot[bot] 9ce5e3ada7 chore(deps): bump google-api-python-client from 2.160.0 to 2.161.0 (#6964)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-19 08:09:33 +05:30
dependabot[bot] 8d08f22604 chore(deps): bump trufflesecurity/trufflehog from 3.88.6 to 3.88.9 (#6957)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 18:40:45 +05:30
dependabot[bot] 349903ab57 chore(deps-dev): bump mkdocs-material from 9.6.3 to 9.6.4 (#6962)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-18 18:38:50 +05:30
Prowler BotandRubén De la Torre Vico 2f077de74a fix(gcp): Correct false positive when sslMode=ENCRYPTED_ONLY in CloudSQL (#6941)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-02-14 16:12:56 -05:00
Prowler BotandSergio Garcia fd642e8d71 fix(gcp): handle DNS Managed Zone with no DNSSEC (#6927)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-13 13:53:31 -05:00
Prowler BotandKay Agahd 4620b07dac fix(aws): codebuild service threw KeyError for projects type CODEPIPELINE (#6929)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-13 13:52:36 -05:00
Prowler BotandOgonna Iwunze c88663b7ef fix(kms): Amazon KMS API call error handling (#6903)
Co-authored-by: Ogonna Iwunze <1915636+wunzeco@users.noreply.github.com>
2025-02-12 11:08:29 -05:00
dependabot[bot] 6197e7b342 chore(deps): bump google-api-python-client from 2.159.0 to 2.160.0 (#6889)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 11:25:35 -05:00
dependabot[bot] e4a596696b chore(deps-dev): bump coverage from 7.6.10 to 7.6.11 (#6891)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 10:25:18 -05:00
dependabot[bot] 7dd436c971 chore(deps-dev): bump mkdocs-material from 9.6.2 to 9.6.3 (#6892)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 19:29:43 -05:00
dependabot[bot] c76fbaef3b chore(deps): bump trufflesecurity/trufflehog from 3.88.4 to 3.88.6 (#6883)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-10 18:15:48 -05:00
Prowler BotandPedro Martín 6b329b1835 fix(dashboard): adjust the bar chart display (#6867)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-07 10:59:27 -05:00
dependabot[bot] d111781387 chore(deps): bump azure-mgmt-web from 7.3.1 to 8.0.0 (#6706)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-07 16:13:41 +01:00
dependabot[bot] 6f68c5cacc chore(deps): bump azure-storage-blob from 12.24.0 to 12.24.1 (#6702)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-07 12:12:49 +01:00
dependabot[bot] a1cfc2d3df chore(deps): bump msgraph-sdk from 1.16.0 to 1.18.0 (#6681)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-07 10:48:44 +01:00
dependabot[bot]andMrCloudSec 958ca6da65 chore(deps-dev): bump black from 24.10.0 to 25.1.0 (#6808)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-05 16:23:35 -05:00
Prowler BotandSergio Garcia a140007ecb fix(kms): handle error in DescribeKey function (#6841)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-05 15:19:39 -05:00
Prowler BotandDaniel Barranquero 75dec160bb fix(cloudfront): fix false positive in s3 origins (#6837)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-05 13:36:44 -05:00
df16872333 fix(findings): Spelling mistakes correction (#6833)
Co-authored-by: Gary Mclean <gary.mclean@krrv.io>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-02-05 11:53:38 -05:00
Prowler BotandDaniel Barranquero 40a1e8abbd fix(directoryservice): handle ClientException (#6827)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-02-05 11:14:35 -05:00
Prowler BotandKay Agahd d623d26e64 fix(aws) wording of report.status_extended in awslambda_function_not_publicly_accessible (#6830)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-02-05 11:13:00 -05:00
dependabot[bot] ca2b6f3ffc chore(deps): bump pytz from 2024.2 to 2025.1 (#6805)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 17:23:08 -05:00
dependabot[bot] c572c8a56d chore(deps-dev): bump mkdocs-material from 9.5.50 to 9.6.2 (#6807)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 16:08:02 -05:00
Prowler BotandHugo Pereira Brito 797abe634a fix(elasticache): InvalidReplicationGroupStateFault error (#6819)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-02-04 16:07:15 -05:00
dependabot[bot] a18b5ff49f chore(deps-dev): bump moto from 5.0.27 to 5.0.28 (#6806)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 14:28:51 -05:00
0e1c6c2d3a chore(aws_audit_manager_control_tower_guardrails): add checks to reqs (#6802)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 14:25:17 -05:00
dependabot[bot]andMrCloudSec fc5b484b27 chore(deps-dev): bump pylint from 3.3.3 to 3.3.4 (#6809)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-02-04 12:58:33 -05:00
dependabot[bot] 2d225de838 chore(deps): bump trufflesecurity/trufflehog from 3.88.2 to 3.88.4 (#6810)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-04 09:58:05 -05:00
dependabot[bot] a332c806bb chore(deps): bump kubernetes from 31.0.0 to 32.0.0 (#6705)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 12:52:03 -05:00
Prowler BotandPedro Martín e236bcecf5 fix(cis_1.5_aws): add checks to needed reqs (#6797)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 11:36:46 -05:00
Prowler BotandPedro Martín 5bf309117a fix(cis_1.4_aws): add checks to needed reqs (#6795)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 11:23:09 -05:00
Prowler Botandsecretcod3r 6cfb68773f fix(gcp): fix wrong provider value in check (#6788)
Co-authored-by: secretcod3r <101349794+secretcod3r@users.noreply.github.com>
2025-02-03 10:20:32 -05:00
Prowler BotandPedro Martín 902d82485a fix(cis_2.0_aws): add checks to needed reqs (#6786)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-02-03 10:20:17 -05:00
dependabot[bot] 5b51a4b2ad chore(deps): bump boto3 from 1.35.98 to 1.35.99 (#6704)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-03 09:28:30 -05:00
Prowler BotandRubén De la Torre Vico 9a5aa8ec06 fix(cloudsql): add trusted client certificates case for cloudsql_instance_ssl_connections (#6684)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-24 12:18:33 -05:00
dependabot[bot]andRubén De la Torre Vico e2d5490700 chore(deps): bump azure-mgmt-compute from 33.1.0 to 34.0.0 (#6638)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
2025-01-24 10:46:50 +01:00
dependabot[bot] 8429c1c36d chore(deps): bump azure-mgmt-containerservice from 33.0.0 to 34.0.0 (#6635)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-24 09:34:34 +01:00
Prowler BotandHugo Pereira Brito 882cd3c25e fix(cloudwatch): NoneType object is not iterable (#6674)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-01-23 13:25:08 -05:00
Prowler BotandKay Agahd 0204d24f5e fix: add detector and line number of potential secret (#6661)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-01-22 10:55:40 -05:00
27fe201a48 chore(deps-dev): bump moto from 5.0.16 to 5.0.27 (#6648)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-21 16:48:28 -05:00
dependabot[bot] a154fb46b8 chore(deps): bump dash-bootstrap-components from 1.6.0 to 1.7.1 (#6633)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 17:54:31 +01:00
dependabot[bot] 530c627ca7 chore(deps): bump botocore from 1.35.98 to 1.35.99 (#6634)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 07:58:38 -05:00
dependabot[bot] 9861c22fe0 chore(deps-dev): bump mkdocs-material from 9.5.49 to 9.5.50 (#6636)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 18:40:47 -05:00
Prowler BotandRubén De la Torre Vico 0a9ea21e11 fix(OCSF): fix OCSF output when timestamp is UNIX format (#6626)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-20 18:03:47 -05:00
Prowler BotandKay Agahd a591beb1bb fix(aws): list tags for DocumentDB clusters (#6621)
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
2025-01-20 16:28:41 -05:00
Prowler BotandRubén De la Torre Vico 967969288f fix: update Azure CIS with existing App checks (#6624)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-20 16:27:27 -05:00
Prowler BotandDaniel Barranquero ddb72cff0f fix(sqs): fix flaky test (#6594)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-01-17 12:36:21 -05:00
Prowler BotandHugo Pereira Brito 240f57278a fix(apigatewayv2): managed exception NotFoundException (#6589)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2025-01-17 09:27:01 -05:00
Prowler BotandDaniel Barranquero b2e322fab7 fix(gcp): fix flaky tests from dns service (#6570)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2025-01-17 08:15:19 -05:00
Prowler BotandPedro Martín 6a38d22634 fix(cis): add subsections if needed (#6567)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-16 11:59:11 -05:00
Prowler BotandPedro Martín 6525c2f17a fix(detect_secrets): refactor logic for detect-secrets (#6565)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-16 11:17:55 -05:00
dependabot[bot] e0698b28d1 chore(deps): bump microsoft-kiota-abstractions from 1.6.8 to 1.7.0 (#6491)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 17:08:12 +01:00
dependabot[bot] 49146ffddf chore(deps-dev): bump bandit from 1.8.0 to 1.8.2 (#6487)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 14:17:41 -05:00
Prowler Botandjohannes-engler-mw b41e23415b fix(Azure TDE): add filter for master DB (#6513)
Co-authored-by: johannes-engler-mw <132657752+johannes-engler-mw@users.noreply.github.com>
2025-01-14 14:16:53 -05:00
dependabot[bot] 55688eaab0 chore(deps): bump boto3 from 1.35.93 to 1.35.98 (#6507)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 11:47:35 -05:00
dependabot[bot] 9c89b13c13 chore(deps): bump botocore from 1.35.95 to 1.35.98 (#6490)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:56:09 -05:00
dependabot[bot] 4db961bad3 chore(deps): bump google-api-python-client from 2.157.0 to 2.159.0 (#6502)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 10:03:18 -05:00
dependabot[bot] e4bf049d06 chore(deps-dev): bump openapi-schema-validator from 0.6.2 to 0.6.3 (#6492)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 08:54:13 -05:00
Prowler BotandPedro Martín 184b4c3f70 fix(iso27001-2013): add ReqId and ReqDescription in output (#6477)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2025-01-13 14:07:23 -05:00
Prowler BotandRubén De la Torre Vico e1620bcb0f fix(vpc): add new principal wildcard verification (#6465)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2025-01-13 10:38:07 -05:00
dependabot[bot]andMrCloudSec a2f3fab936 chore(deps): bump botocore from 1.35.93 to 1.35.95 (#6427)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-10 14:21:59 -05:00
dependabot[bot] 0cd2ad5636 chore(deps): bump trufflesecurity/trufflehog from 3.88.1 to 3.88.2 (#6415)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-09 10:33:51 -05:00
Prowler BotandSergio Garcia 6fab9a89fd fix(iam): handle non existing MFA devices (#6407)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2025-01-09 10:31:39 -05:00
dependabot[bot] 87f5d32bb3 chore(deps): bump azure-mgmt-network from 28.0.0 to 28.1.0 (#6309)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 13:56:19 -05:00
dependabot[bot] 6540facaea chore(deps): bump microsoft-kiota-abstractions from 1.6.6 to 1.6.8 (#6359)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 12:40:01 -05:00
dependabot[bot] d11b5f8f12 chore(deps): bump msgraph-sdk from 1.14.0 to 1.16.0 (#6361)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 11:40:14 -05:00
dependabot[bot] 8a982afe21 chore(deps-dev): bump coverage from 7.6.9 to 7.6.10 (#6332)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 10:46:21 -05:00
dependabot[bot] f3303974d3 chore(deps): bump google-api-python-client from 2.156.0 to 2.157.0 (#6377)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 09:22:39 -05:00
dependabot[bot] c69f0a0085 chore(deps): bump boto3 from 1.35.87 to 1.35.93 (#6380)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 13:03:20 +01:00
dependabot[bot] 9c9df486f0 chore(deps): bump botocore from 1.35.90 to 1.35.93 (#6379)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 20:11:46 -05:00
dependabot[bot] e12aa389a3 chore(deps): bump trufflesecurity/trufflehog from 3.88.0 to 3.88.1 (#6375)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 18:08:58 -05:00
dependabot[bot]andMrCloudSec e8db8525ab chore(deps-dev): bump pylint from 3.3.2 to 3.3.3 (#6333)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-06 16:34:46 -05:00
87e9b0f807 fix(aws): add missing sqs service without subservice (#6364)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2025-01-06 15:38:38 -05:00
dependabot[bot] 65b2a81226 chore(deps): bump botocore from 1.35.87 to 1.35.90 (#6331)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 10:17:08 -05:00
dependabot[bot] ad63b6991e chore(deps): bump google-api-python-client from 2.155.0 to 2.156.0 (#6312)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 19:00:43 -05:00
dependabot[bot] b536be1c56 chore(deps): bump slack-sdk from 3.33.5 to 3.34.0 (#6314)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 13:50:23 -05:00
dependabot[bot] 6b078fd668 chore(deps): bump trufflesecurity/trufflehog from 3.86.1 to 3.88.0 (#6315)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 09:20:17 -05:00
dependabot[bot] 436521d932 chore(deps): bump boto3 from 1.35.80 to 1.35.87 (#6319)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 09:17:57 -05:00
dependabot[bot] ee09ccb4aa chore(deps): bump botocore from 1.35.82 to 1.35.87 (#6313)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 08:12:01 -05:00
Prowler Bot 52406f6df2 fix(aws): disallow child-accounts to overwrite policy for ai_services_opt_out (#6291) 2024-12-20 11:53:15 -05:00
Prowler BotandSergio Garcia 7687148a27 fix(aws): add missing region to Backup Recovery Point (#6274)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-19 16:55:48 -05:00
Prowler BotandSergio Garcia 44b7fc4624 fix(aws): solve None type errors (#6271)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-19 12:19:56 -05:00
dependabot[bot] 68050d3df3 chore(deps): bump azure-mgmt-compute from 33.0.0 to 33.1.0 (#6213)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-19 15:13:59 +01:00
dependabot[bot] 47fe1b77e2 chore(deps): bump botocore from 1.35.80 to 1.35.82 (#6214)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 10:00:22 -05:00
dependabot[bot] 04057e8911 chore(deps): bump boto3 from 1.35.77 to 1.35.80 (#6212)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 09:41:56 +01:00
dependabot[bot] 401fdec1fb chore(deps-dev): bump mkdocs-material from 9.5.48 to 9.5.49 (#6215)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 08:42:37 +01:00
4e556c86ef fix(deploy): temporal fix for the alpine-python segmentation fault (#6179)
Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com>
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2024-12-13 14:17:40 +01:00
dependabot[bot] 72c8de3e67 chore(deps): bump botocore from 1.35.77 to 1.35.80 (#6187)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 14:09:40 +01:00
Prowler BotandSergio Garcia 3786cbcd5f fix(aws): set unique resource IDs (#6191)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-13 09:07:39 -04:00
dependabot[bot] 1084b00ef7 chore(deps): bump google-api-python-client from 2.154.0 to 2.155.0 (#6189)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 13:19:50 +01:00
dependabot[bot] 7f5ddcc215 chore(deps): bump trufflesecurity/trufflehog from 3.85.0 to 3.86.1 (#6184)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 12:24:45 +01:00
Prowler BotandPedro Martín 60b8f9d3b9 fix(rds): add invalid SG to status_extended (#6169)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2024-12-12 12:47:08 -04:00
Prowler BotandMads Brouer Lundholm 4c4f12ffda fix(aurora): Add default ports to the check of using non default ports (#6150)
Co-authored-by: Mads Brouer Lundholm <mads@madslundholm.dk>
2024-12-11 14:58:29 -04:00
Prowler BotandDaniel Barranquero 4c0729378d fix(autoscaling): autoscaling_group_launch_configuration_requires_imdsv2 fails if Launch Template is used (#6146)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2024-12-11 12:06:35 -04:00
Sergio Garcia fda49bec18 chore(version): update Prowler v4 version (#6140) 2024-12-11 16:02:04 +01:00
Prowler BotandRubén De la Torre Vico 9606cf21eb fix(app): add support for TLS 1.3 to Web Apps check (#6143)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-12-11 10:28:53 -04:00
Prowler BotandSergio Garcia d3da9dd90e fix(iam): set unique resource id for each user access key (#6133)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-11 09:25:40 -04:00
Prowler BotandPedro Martín 4fb010847f fix(compliance_tables): add correct values for findings (#6126)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2024-12-10 16:47:16 -04:00
Prowler BotandHugo Pereira Brito 8eac17d826 fix(aws): get firewall manager managed rule groups (#6123)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2024-12-10 16:47:01 -04:00
dependabot[bot] 8a1abb60c9 chore(deps-dev): bump pytest from 8.3.3 to 8.3.4 (#6075)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 14:38:57 -04:00
Prowler BotandHugo Pereira Brito 74776bed06 fix(aws): check AWS Owned keys in firehose_stream_encrypted_at_rest (#6120)
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
2024-12-10 14:30:45 -04:00
dependabot[bot] 3373a8e6c8 chore(deps): bump microsoft-kiota-abstractions from 1.6.2 to 1.6.6 (#6080)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 13:48:43 -04:00
Prowler BotandSergio Garcia 7db74516b3 fix(aws): set IAM identity as resource in threat detection (#6117)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-10 13:37:27 -04:00
Prowler BotandSergio Garcia 3ae2f9e0bf fix(gcp): make sure default project is active (#6112)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-10 11:53:28 -04:00
dependabot[bot] 91a8a13dc6 chore(deps): bump msgraph-sdk from 1.12.0 to 1.14.0 (#6074)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 11:42:18 -04:00
dependabot[bot] 700ed5ecec chore(deps-dev): bump pylint from 3.3.1 to 3.3.2 (#6099)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 10:36:15 -04:00
Prowler BotandSergio Garcia 50aebcaf88 fix(aws): set same severity for EC2 IMDSv2 checks (#6103)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-10 09:30:34 -04:00
dependabot[bot] ad96963706 chore(deps): bump boto3 from 1.35.66 to 1.35.77 (#6107)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 09:26:53 -04:00
dependabot[bot] 95832bdb12 chore(deps): bump botocore from 1.35.76 to 1.35.77 (#6100)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 10:55:31 +01:00
dependabot[bot] d7bdc0aaef chore(deps-dev): bump bandit from 1.7.10 to 1.8.0 (#6072)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 17:39:53 -04:00
dependabot[bot] 1c0c836286 chore(deps-dev): bump coverage from 7.6.7 to 7.6.9 (#6076)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 16:51:09 -04:00
dependabot[bot] 822252d03b chore(deps): bump slack-sdk from 3.33.4 to 3.33.5 (#6077)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 15:53:24 -04:00
dependabot[bot] a20fdb30f9 chore(deps-dev): bump mkdocs-material from 9.5.45 to 9.5.48 (#6078)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 14:44:08 -04:00
dependabot[bot] 2e339f964a chore(deps): bump botocore from 1.35.66 to 1.35.76 (#6071)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 13:38:26 -04:00
Sergio Garcia bb4498a3d5 chore(container): upload v4 with correct tags (#6093) 2024-12-09 18:38:14 +01:00
dae4392efc fix(backup): modify list recovery points call (#6057)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-09 12:55:12 -04:00
dependabot[bot]andMrCloudSec 8b3a1608c2 chore(deps-dev): bump vulture from 2.13 to 2.14 (#6069)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-12-09 12:22:48 -04:00
148bdacebe chore(containers): support for v4.6 branch (#6084)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-09 11:23:06 -04:00
Prowler BotandSergio Garcia b60edc1f6b fix(tests): use datetime.datetime.now() in GCP kms_key_rotation_enabled (#6083)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-12-09 11:06:37 -04:00
Prowler BotandPepe Fagoaga d28462b642 chore(dependabot): Update for UI and v4 (#6087)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-12-09 10:45:24 -04:00
dependabot[bot] ef9b37d5c0 chore(deps): bump trufflesecurity/trufflehog from 3.84.1 to 3.85.0 (#6067)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 09:28:22 -04:00
Sergio Garcia 764f260cea chore(version): update Prowler version (#5969) 2024-11-29 13:14:08 -04:00
Prowler BotandSergio Garcia e771218bba fix(k8s): handle Kubernetes kubeconfig content correctly (#5967)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-29 10:19:00 -04:00
Prowler BotandStylusFrost c627a3e9aa fix(azure): containerregistry_not_publicly_accesible is not accurate (#5966)
Co-authored-by: StylusFrost <43682773+StylusFrost@users.noreply.github.com>
2024-11-29 09:53:06 -04:00
Prowler BotandRubén De la Torre Vico 1c58644118 fix(rds): add default key value to RDS event (#5965)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-11-29 09:52:55 -04:00
Prowler BotandSergio Garcia 398fa37a23 fix(gcp): use session credentials to check if API is active (#5936)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-27 16:58:40 -04:00
Prowler BotandSergio Garcia 412d948585 fix(aws): exclude threat detection checks if category not present (#5934)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-27 12:56:00 -04:00
Prowler BotandPepe Fagoaga 6bc0432ed5 fix(list_by_service): execute lambda if requested (#5931)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-11-27 11:22:49 -04:00
Pepe Fagoaga b2ebc8410a chore(version): update Prowler v4 version (#5901) 2024-11-26 08:11:16 -04:00
Prowler BotandSergio Garcia 94b6fbda91 chore(gcp): update docstring of ADC credentials (#5879)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-25 13:54:40 -04:00
Prowler BotandDaniel Barranquero 3ce785a7b4 chore(aws): update fixers docstring (#5878)
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2024-11-25 13:01:45 -04:00
dependabot[bot] e4ecc98aae chore(deps): bump trufflesecurity/trufflehog from 3.84.0 to 3.84.1 (#5870)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 09:02:32 -04:00
sansns-awsandMrCloudSec 53a4befb01 feat(aws): add MemoryDB service (#5546)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-11-22 15:13:16 -04:00
fee0bf3ea1 feat(azure): AI Search service check not publicly accesible (#5846)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-11-22 13:28:44 -04:00
Daniel Barranquero 6811a22651 feat(documentdb): add new fixer documentdb_cluster_public_snapshot_fixer (#5759) 2024-11-22 11:14:24 -04:00
Daniel Barranquero fe2dd69b08 feat(neptune): add new fixer neptune_cluster_public_snapshot_fixer (#5749) 2024-11-22 11:13:18 -04:00
dependabot[bot] 26a9748700 chore(deps): bump boto3 from 1.35.65 to 1.35.66 (#5860)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-22 10:34:44 -04:00
Prowler Botandsergargar cef0a54bc3 chore(regions_update): Changes in regions for AWS services (#5863)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-22 10:34:24 -04:00
dependabot[bot] 553a51ddc2 chore(deps): bump trufflesecurity/trufflehog from 3.83.7 to 3.84.0 (#5862)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-22 10:33:58 -04:00
Gary McleanandPedro Martín 61dc09d15d Fix CIS details for new EFS Controls (#5858)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
2024-11-22 11:55:21 +01:00
dependabot[bot] 9b91ba2b91 chore(deps): bump azure-mgmt-cosmosdb from 9.6.0 to 9.7.0 (#5834)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 14:22:28 -04:00
dependabot[bot] 18d60c98d7 chore(deps): bump botocore from 1.35.65 to 1.35.66 (#5850)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 12:40:45 -04:00
Daniel BarranqueroandSergio Garcia 00054b5cd9 feat(ec2): add new fixer ec2_ebs_public_snapshot_fixer (#5825)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-21 12:40:28 -04:00
Pedro Martín 24fc86cbb3 fix(severity): add enum for severity values (#5856) 2024-11-21 12:28:20 -04:00
Daniel Barranquero 861fb22257 feat(kms): add new fixer kms_cmk_not_deleted_unintentionally_fixer (#5842) 2024-11-21 11:45:55 -04:00
dependabot[bot] 7e14204be8 chore(deps): bump boto3 from 1.35.64 to 1.35.65 (#5853)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 11:44:04 -04:00
Daniel Barranquero 09ea6ba6c4 feat(rds): add new fixer rds_instance_no_public_access_fixer (#5794) 2024-11-21 11:42:03 -04:00
dependabot[bot] a83725fbed chore(deps-dev): bump mkdocs-material from 9.5.44 to 9.5.45 (#5852)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 10:34:11 -04:00
dependabot[bot] 34210cfc06 chore(deps): bump google-api-python-client from 2.153.0 to 2.154.0 (#5851)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-21 09:22:35 -04:00
Pedro Martín 2e20d52030 feat(compliance): add ENSRD2022 for Azure and GCP (#5746) 2024-11-21 09:36:47 +01:00
sansns-awsandMrCloudSec 9b0b61ef02 feat(sgw): add storagegateway_fault_tolerance check (#5570)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-11-20 15:10:44 -04:00
dependabot[bot] 0203aec9e0 chore(deps): bump botocore from 1.35.64 to 1.35.65 (#5836)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 11:06:49 -04:00
dependabot[bot] 862a4ad76c chore(deps): bump slack-sdk from 3.33.3 to 3.33.4 (#5837)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 10:17:30 -04:00
Sergio Garcia 4b7883c464 fix(kubernetes): filter apiGroup in permission checks (#5829) 2024-11-20 15:06:06 +01:00
dependabot[bot] 2bf835d3d2 chore(deps): bump boto3 from 1.35.63 to 1.35.64 (#5835)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 09:29:24 -04:00
Prowler Botandsergargar 09733eb298 chore(regions_update): Changes in regions for AWS services (#5839)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-20 09:29:03 -04:00
Pedro Martín 096749a455 refactor(arn): fine tune arn and resources id for unknown values (#5841) 2024-11-20 12:56:51 +01:00
Pedro MartínandSergio Garcia b06e549d81 refactor(arn): refactor arn for unknown resources (#5712)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-19 16:21:43 -04:00
Sergio Garcia a5f5967bb2 fix(aws): exclude member accounts in IAM Root Credentials check (#5813) 2024-11-19 15:06:12 +01:00
Sergio Garcia 7a4f5f34f7 fix(kubernetes): validate seccomp profile at pod and container levels (#5814) 2024-11-19 15:04:30 +01:00
Rubén De la Torre Vico e33b081dc6 chore(iam): add exception for public policy in EKS service (#4759) 2024-11-19 09:42:56 -04:00
Prowler Botandsergargar c8fdaa3923 chore(regions_update): Changes in regions for AWS services (#5824)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-19 09:24:49 -04:00
dependabot[bot] 8a491bcf7d chore(deps): bump trufflesecurity/trufflehog from 3.83.6 to 3.83.7 (#5819)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-19 09:24:32 -04:00
Daniel Barranquero f5e71db5e0 fix(rds): fix typo error in rds_snapshots_public_access_fixer test (#5826) 2024-11-19 09:23:52 -04:00
dependabot[bot] 456f79d80c chore(deps): bump botocore from 1.35.63 to 1.35.64 (#5818)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-19 09:52:56 +01:00
Sergio Garcia 9f728833a7 chore(iam): add missing service catalog permissions (#5816) 2024-11-19 09:21:20 +01:00
dependabot[bot] f01ce849dc chore(deps): bump aiohttp from 3.10.10 to 3.10.11 (#5815)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 18:35:48 -04:00
Hugo Pereira Brito 572d5a1f2e fix(wafv2): only list resources for regional Web ACLs (#5811) 2024-11-18 12:09:23 -04:00
Sergio Garcia c69571abcd feat(aws): add new check iam_root_credentials_management_enabled (#5801) 2024-11-18 16:59:35 +01:00
dependabot[bot] 8ddb9fbb84 chore(deps): bump boto3 from 1.35.60 to 1.35.63 (#5809)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 11:27:20 -04:00
dependabot[bot] 193b79c221 chore(deps-dev): bump coverage from 7.6.6 to 7.6.7 (#5795)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 10:36:03 -04:00
Pedro Martín a25a6148f2 docs(gcp): improve docstrings (#5716) 2024-11-18 15:19:15 +01:00
Pedro Martín 0a63e707c2 docs(kubernetes): improve docstrings for methods (#5717) 2024-11-18 15:18:57 +01:00
dependabot[bot] f53a887291 chore(deps): bump botocore from 1.35.61 to 1.35.63 (#5797)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 09:37:53 -04:00
Prowler Botandsergargar ca35510d74 chore(regions_update): Changes in regions for AWS services (#5802)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-18 09:37:25 -04:00
Pedro MartínandPepe Fagoaga 5d7c8d9cd2 docs(aws): improve docstrings (#5714)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-11-18 12:17:05 +01:00
Pedro Martín 0d01790b22 docs(azure): improve docstrings (#5715) 2024-11-18 10:46:34 +01:00
dependabot[bot] 78b518e22b chore(deps-dev): bump coverage from 7.6.4 to 7.6.6 (#5793)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-15 10:23:35 -05:00
Pepe Fagoaga 17af724995 chore(labeler): Add compliance (#5790) 2024-11-15 10:16:03 -05:00
dependabot[bot] c9898d6d01 chore(deps): bump codecov/codecov-action from 4 to 5 (#5783)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-15 09:35:54 -05:00
Prowler Botandsergargar 259538d5e4 chore(regions_update): Changes in regions for AWS services (#5784)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-15 09:33:24 -05:00
dependabot[bot] 4785feae0e chore(deps): bump botocore from 1.35.60 to 1.35.61 (#5780)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-15 09:33:05 -05:00
Pedro Martín 8be83fc632 fix(compliance): use SubscriptionID instead of name for Azure CIS (#5786) 2024-11-15 14:40:33 +01:00
Pedro Martín 005d251106 fix(iam): use get to get the key (#5785) 2024-11-15 14:37:36 +01:00
dependabot[bot] b6c8adfc64 chore(deps): bump azure-storage-blob from 12.23.1 to 12.24.0 (#5767)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-14 12:01:27 -05:00
Hugo Pereira BritoandSergio Garcia 7a711095cd feat(kinesis): add new check kinesis_stream_data_retention_period (#5547)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-14 12:01:01 -05:00
Daniel Barranquero b0bb348480 feat(rds): add new fixer rds_snapshots_public_access_fixer (#5773) 2024-11-14 10:40:33 -05:00
Hugo Pereira BritoandSergio Garcia c1b050b8b9 feat(firehose): add new check firehose_stream_encrypted_at_rest (#5635)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
2024-11-14 10:27:17 -05:00
Víctor Fernández Poyatos 28c7e803ac feat(azure): Add get_regions method for provider (#5774) 2024-11-14 15:58:12 +01:00
Prowler Botandsergargar 919acfd548 chore(regions_update): Changes in regions for AWS services (#5771)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-14 08:57:26 -05:00
dependabot[bot] 1586cdae5e chore(deps): bump google-api-python-client from 2.152.0 to 2.153.0 (#5763)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-14 08:57:09 -05:00
Pepe Fagoaga cb74dae296 refactor(aws): Rename get_regions and validate partition (#5772) 2024-11-14 13:02:32 +01:00
dependabot[bot] 3608aa3536 chore(deps): bump boto3 from 1.35.58 to 1.35.60 (#5770)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-14 10:01:57 +01:00
dependabot[bot] c59b08c40b chore(deps): bump botocore from 1.35.59 to 1.35.60 (#5765)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 19:11:52 -05:00
Rubén De la Torre VicoandMrCloudSec 73361a1cea chore(ec2): add name from image information to status_extended (#5755)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-11-13 14:30:58 -05:00
Pedro Martín 794268cec5 feat(gcp): add get regions method (#5756) 2024-11-13 19:11:42 +01:00
Pedro Martín 06b41cf8e6 refactor(azure): get locations with self session (#5751) 2024-11-13 19:00:18 +01:00
Pedro Martín a419b4b898 feat(aws): get regions by partition (#5748) 2024-11-13 18:52:50 +01:00
Rubén De la Torre Vico 622bc48688 fix(ec2): add default value to Name key for image information (#5747) 2024-11-13 15:22:52 +01:00
dependabot[bot] c0659f712a chore(deps): bump botocore from 1.35.58 to 1.35.59 (#5740)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 09:20:49 -05:00
Sergio Garcia 796983a530 fix(gcp): scan only ACTIVE projects (#5743) 2024-11-13 15:18:42 +01:00
Prowler Botandsergargar 8dc042e594 chore(regions_update): Changes in regions for AWS services (#5744)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-13 08:13:35 -05:00
dependabot[bot] e881a0f274 chore(deps): bump google-api-python-client from 2.151.0 to 2.152.0 (#5742)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 08:13:18 -05:00
dependabot[bot] 5641160177 chore(deps): bump boto3 from 1.35.57 to 1.35.58 (#5741)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 18:17:31 -05:00
Hugo Pereira BritoandMrCloudSec dca49b1972 feat(aws): add new service firehose (#5620)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
2024-11-12 17:41:46 -05:00
Rubén De la Torre VicoandSergio b8b60e6bc5 feat(prowler-check-kreator): ProwlerChecKreator first version (#5099)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-12 15:00:09 -05:00
9d65b49cb4 chore(deps): bump azure-mgmt-network from 27.0.0 to 28.0.0 (#5703)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com>
Co-authored-by: Sergio Garcia <38561120+MrCloudSec@users.noreply.github.com>
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-12 13:37:51 -05:00
Sergio Garcia f1334190d8 fix(aws): remove cloudwatch_log_group_no_critical_pii_in_logs check (#5736) 2024-11-12 12:50:47 -05:00
dependabot[bot] c434181dfd chore(deps): bump azure-mgmt-containerservice from 32.1.0 to 33.0.0 (#5706)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 11:43:21 -05:00
dependabot[bot] f3cfacae9a chore(deps): bump msgraph-sdk from 1.11.0 to 1.12.0 (#5722)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 10:26:10 -05:00
sansns-aws 77c7986797 feat(aws): Update check metadata with logging category (#5639) 2024-11-12 09:26:52 -05:00
Prowler Botandsergargar 2ac716d6db chore(regions_update): Changes in regions for AWS services (#5732)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-12 09:25:12 -05:00
dependabot[bot] daee5fb4d2 chore(deps): bump microsoft-kiota-abstractions from 1.6.0 to 1.6.2 (#5720)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-12 13:46:19 +01:00
dependabot[bot] d587d40451 chore(deps): bump botocore from 1.35.57 to 1.35.58 (#5721)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 19:32:42 -05:00
dependabot[bot] f0cd88bd0e chore(deps): bump trufflesecurity/trufflehog from 3.83.5 to 3.83.6 (#5723)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 19:32:13 -05:00
dependabot[bot] aca17904fa chore(deps-dev): bump mkdocs-git-revision-date-localized-plugin from 1.2.9 to 1.3.0 (#5704)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 14:24:40 -05:00
dependabot[bot] 0157802ac1 chore(deps-dev): bump pytest-randomly from 3.15.0 to 3.16.0 (#5705)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 12:12:44 -05:00
sansns-awsandSergio 10766d708d feat(mq): add mq_broker_not_publicly_accessible check (#5604)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-11 12:12:21 -05:00
Mario Rodriguez LopezandSergio Garcia f231d8b080 feat(appsync): add new check appsync_field_level_logging_enabled (#5602)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-11 10:23:13 -05:00
dependabot[bot] 590a7b2697 chore(deps): bump boto3 from 1.35.55 to 1.35.57 (#5719)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 10:04:32 -05:00
Hugo Pereira Brito 3c3421644f fix(docs): provider typo (#5713) 2024-11-11 09:21:54 -05:00
Pedro MartínandPepe Fagoaga f1f68da25d feat(jira): add jira integration (#5629)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-11-11 15:00:31 +01:00
Prowler Botandsergargar 48df7fdebf chore(regions_update): Changes in regions for AWS services (#5709)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-11 08:51:17 -05:00
dependabot[bot] f2e8691bf4 chore(deps): bump botocore from 1.35.56 to 1.35.57 (#5702)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 08:50:28 -05:00
Matt Johnson 344d54155a docs: Update contact.md with new Slack join URL (#5671) 2024-11-11 12:06:16 +01:00
dependabot[bot] 8ecffa3039 chore(deps): bump trufflesecurity/trufflehog from 3.83.4 to 3.83.5 (#5708)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 10:11:40 +01:00
dependabot[bot] efbbfc1c68 chore(deps): bump azure-mgmt-resource from 23.1.1 to 23.2.0 (#5684)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 15:18:01 -05:00
dependabot[bot] dc68c1b955 chore(deps): bump msgraph-sdk from 1.8.0 to 1.11.0 (#5687)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 14:09:14 -05:00
Mario Rodriguez Lopez 5de13bdd8a fix(ec2): unique finding per Security Group in high risk ports check (#5697) 2024-11-08 14:08:27 -05:00
dependabot[bot] 5d0f498425 chore(deps): bump botocore from 1.35.55 to 1.35.56 (#5683)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 12:41:05 -05:00
Mario Rodriguez LopezandSergio Garcia 716558ffcb feat(servicecatalog): Add new check servicecatalog_portfolio_shared_within_organization_only (#5632)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-08 12:22:13 -05:00
dependabot[bot] 23929b3e68 chore(deps): bump dash from 2.18.1 to 2.18.2 (#5682)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 11:50:17 -05:00
dependabot[bot] a5612abc8c chore(deps-dev): bump safety from 3.2.8 to 3.2.9 (#5681)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 10:54:18 -05:00
Prowler Botandsergargar 78dddc1e03 chore(regions_update): Changes in regions for AWS services (#5694)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-08 10:53:57 -05:00
dependabot[bot] 76020d4d47 chore(deps): bump alive-progress from 3.1.5 to 3.2.0 (#5689)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 09:54:57 -05:00
dependabot[bot] b0af1390b5 chore(deps): bump trufflesecurity/trufflehog from 3.83.3 to 3.83.4 (#5692)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 11:48:59 +01:00
dependabot[bot] bc3cd43126 chore(deps): bump slack-sdk from 3.33.1 to 3.33.3 (#5688)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 11:19:02 +01:00
dependabot[bot] 087dae07d8 chore(deps-dev): bump coverage from 7.6.1 to 7.6.4 (#5686)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 09:04:20 +01:00
dependabot[bot] 0baf4fb224 chore(deps): bump boto3 from 1.35.29 to 1.35.55 (#5685)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-08 08:15:43 +01:00
dependabot[bot] 0f8ea48f2f chore(deps): bump azure-mgmt-containerservice from 32.0.0 to 32.1.0 (#5664)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 15:49:57 -05:00
dependabot[bot] ec207c50ce chore(deps): bump microsoft-kiota-abstractions from 1.3.3 to 1.6.0 (#5662)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 14:54:13 -05:00
dependabot[bot] b59b40b822 chore(deps): bump azure-keyvault-keys from 4.9.0 to 4.10.0 (#5660)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 13:26:51 -05:00
dependabot[bot] aa51045329 chore(deps-dev): bump mkdocs-material from 9.5.39 to 9.5.44 (#5659)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 12:36:15 -05:00
dependabot[bot] 1a9f854063 chore(deps): bump google-api-python-client from 2.147.0 to 2.151.0 (#5661)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 11:42:31 -05:00
Mario Rodriguez LopezandSergio Garcia 6bdcb509e1 feat(appsync): add new check appsync_graphql_apis_no_api_key_authentication (#5591)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-07 11:42:07 -05:00
Sergio Garcia ce1e9de104 chore(aws): deprecate glue_etl_jobs_logging_enabled check (#5670) 2024-11-07 10:25:32 -05:00
dependabot[bot] 2471bc569a chore(deps): bump botocore from 1.35.29 to 1.35.55 (#5663)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 10:22:14 -05:00
Daniel BarranqueroandSergio d0ef75d8d9 feat(dms): add new check dms_replication_task_target_logging_enabled (#5631)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-07 10:19:44 -05:00
Sergio Garcia aa79a289ce fix(aws): update EKS check in compliance frameworks (#5672) 2024-11-07 15:56:55 +01:00
dependabot[bot] 0340ab9570 chore(deps-dev): bump pytest-cov from 5.0.0 to 6.0.0 (#5666)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 09:17:18 -05:00
thomscodeandPepe Fagoaga a2929f2efb fix(mutelist): set arguments while loading providers (#5653)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-11-07 09:12:29 -05:00
Prowler Botandsergargar bf4db86dec chore(regions_update): Changes in regions for AWS services (#5655)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-07 08:22:22 -05:00
Daniel Barranquero a339dafcc6 fix(guardduty): fix guardduty_is_enabled_fixer test (#5668) 2024-11-07 08:21:49 -05:00
dependabot[bot] f376516aad chore(deps-dev): bump vulture from 2.12 to 2.13 (#5665)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 08:20:54 -05:00
dependabot[bot] 816b49fac5 chore(deps-dev): bump black from 24.8.0 to 24.10.0 (#5667)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-07 12:55:16 +01:00
Pepe Fagoaga 6851350093 fix(lock): Use detect-secrets from package not repo (#5656) 2024-11-07 11:30:46 +01:00
Daniel BarranqueroandSergio d5873c0437 feat(dms): add new check dms_replication_task_source_logging_enabled (#5627)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-06 15:50:48 -05:00
Mario Rodriguez LopezandSergio a2dba30869 feat(servicecatalog): Add new service servicecatalog (#5618)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-06 12:02:14 -05:00
Mario Rodriguez LopezandSergio 0662dff13f feat(appsync): Add new service AppSync (#5589)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-06 11:50:27 -05:00
Daniel BarranqueroandSergio Garcia 0ae26bddfc feat(dms): add new check dms_endpoint_redis_tls_enabled (#5583)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-06 11:03:13 -05:00
Sergio Garcia 43efabef6c fix(docker): add g++ to Dockerfile for presidio-analyzer compatibility (#5645) 2024-11-06 10:45:16 -05:00
dependabot[bot] e73fc14f62 chore(deps): bump trufflesecurity/trufflehog from 3.83.2 to 3.83.3 (#5647)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-06 10:13:09 +01:00
Sergio Garcia 89fe8fa8e2 chore(version): update Prowler version (#5642) 2024-11-06 08:11:13 +01:00
Drew Kerrigan 634ef2e599 fix(docs): Update misc tutorial categories example (#5644) 2024-11-05 15:37:20 -05:00
Sergio Garcia 4efb70a508 chore(README): update summary table (#5633) 2024-11-05 13:24:46 -05:00
Pepe Fagoaga c3ae0aa873 fix(connection): return Connection on generic exception (#5636) 2024-11-05 12:24:18 -05:00
Sergio Garcia a109cd2816 fix(gcp): do not require organization id to get projects (#5637) 2024-11-05 12:24:07 -05:00
sansns-aws 78fb540bbb feat(rds): add rds_cluster_protected_by_backup_plan check (#5638) 2024-11-05 11:30:45 -05:00
sansns-aws 5b543bf058 feat(aws): Update check metadata with redudancy category (#5640) 2024-11-05 11:27:24 -05:00
Daniel BarranqueroandSergio Garcia 9802fc141a feat(dms): add new check dms_endpoint_mongodb_authentication_enabled (#5578)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-05 09:58:55 -05:00
Daniel BarranqueroandSergio Garcia ea038085ba feat(dms): add new check dms_endpoint_neptune_iam_authorization_enabled (#5549)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-05 08:43:57 -05:00
Sergio Garcia 6ff1c436a0 fix(aws): handle global WAFv2 ACLs in service (#5628) 2024-11-05 08:42:20 -05:00
Rubén De la Torre VicoandSergio 1b50fdba28 feat(secretsmanager): add new check secretsmanager_secret_rotated_periodically (#5450)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-04 16:08:38 -05:00
Sergio Garcia 230d2571f9 fix(k8s): do not raise error when unable to list roles (#5630) 2024-11-04 13:47:18 -05:00
sansns-awsandSergio 6c818cbcc3 fix(rds): Check Aurora clusters properly for backup plan (#5594)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-04 13:20:22 -05:00
Mario Rodriguez LopezandSergio Garcia 694cee1afb feat(kafka): add new check kafka_connector_in_transit_encryption_enabled (#5577)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-11-04 12:46:32 -05:00
Mario Rodriguez LopezandSergio bc89f4383e feat(ecs): add new check ecs_task_set_no_assign_public_ip (#5603)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-04 11:49:22 -05:00
Sergio Garcia 84d4e4a604 fix(aws): solve invalid ECR Registry ARN (#5622) 2024-11-04 11:47:49 -05:00
Hugo Pereira BritoandSergio 5fbf8ddfe9 feat(transfer): add new check transfer_server_encryption_in_transit (#5590)
Co-authored-by: Sergio <sergio@prowler.com>
2024-11-04 11:30:18 -05:00
Prowler Botandsergargar ddcd06d9be chore(regions_update): Changes in regions for AWS services (#5617)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-04 11:20:16 -05:00
Pepe Fagoaga 5214a37d6d chore: add dependabot labels (#5624) 2024-11-04 10:45:53 -05:00
sansns-aws a1f4ae73cf feat(aws): Update check metadata with category (#5607) 2024-11-04 10:45:36 -05:00
Prowler Botandsergargar d0bc37c281 chore(regions_update): Changes in regions for AWS services (#5600)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-04 10:24:55 -05:00
Prowler Botandsergargar 85393e6f78 chore(regions_update): Changes in regions for AWS services (#5613)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-11-04 10:20:42 -05:00
Sergio Garcia e3104ae5ee feat(aws): add new check cloudwatch_log_group_no_critical_pii_in_logs (#5494) 2024-11-04 10:20:35 -05:00
Sergio Garcia be523c11c8 fix(aws): do not flag cross-service confused deputy as public (#5593) 2024-11-04 15:51:52 +01:00
Hugo Pereira Brito 797b627695 feat(aws): add new service transfer (#5585) 2024-11-04 08:55:47 -05:00
dependabot[bot] 5ac670ed4f chore(deps): bump trufflesecurity/trufflehog from 3.82.13 to 3.83.2 (#5611)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 08:51:15 -05:00
Pedro Martín bf9111397b feat(mutelist): add mute_finding method (#5563) 2024-11-04 12:05:03 +01:00
Pedro Martín 17dd9de6d8 fix(main): set attributes on load_checks_to_execute (#5606) 2024-11-04 09:05:02 +01:00
Pedro Martín e4400ecf10 fix(checks_loader): solve issue related with checks from compliance (#5601) 2024-10-31 17:28:23 +01:00
sansns-aws cbba5acc31 chore(aws): cleanup tests in dynamodb and cw (#5588) 2024-10-31 07:59:33 +01:00
Mario Rodriguez LopezandSergio 046f1b2e5f feat(guardduty): add new check guardduty_eks_runtime_monitoring_enabled (#5582)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-30 15:01:50 -05:00
sansns-awsandSergio 9e8f88c889 feat(elbv2): add elbv2_nlb_tls_termination_enabled check (#5550)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-30 15:00:55 -05:00
sansns-awsandSergio 2d73b9b8f4 feat(elbv2): add elbv2_cross_zone_load_balancing_enabled check (#5548)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-30 14:42:56 -05:00
sansns-aws 9a7190c9c2 chore(aws): cleanup tests (#5592) 2024-10-30 14:04:05 -05:00
sansns-aws a2b6bdc461 feat(ecs): Add ecs_task_definitions_logging_block_mode check (#5526) 2024-10-30 12:02:36 -05:00
Hugo Pereira BritoandSergio 056d482023 feat(glue): add new check glue_etl_jobs_logging_enabled (#5581)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-30 10:56:46 -05:00
Sergio Garcia 239b248935 feat(aws): add new check bedrock_agent_guardrail_enabled (#5509) 2024-10-30 09:41:44 -05:00
Sergio Garcia 5bd394dffe fix(gcp): enforce correct severity levels in CloudSQL PostgreSQL log_min_messages (#5571) 2024-10-30 09:41:06 -05:00
Prowler Botandsergargar 1195b75acc chore(regions_update): Changes in regions for AWS services (#5580)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-30 09:03:02 -05:00
Daniel Barranquero fee70bc9b4 chore(rds): improve metadata title and description for check rds_instance_transport_encrypted (#5584) 2024-10-30 09:02:03 -05:00
Sergio GarciaandRubén De la Torre Vico 01716d9020 feat(aws): add new check cloudwatch_log_group_not_publicly_accessible (#5495)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-10-30 08:50:17 -05:00
Pedro Martín b87e6d20d7 feat(s3): add test_connection method (#5332) 2024-10-30 11:45:22 +01:00
Pedro Martín 11592634f2 fix(check): add .value to severity enum (#5579) 2024-10-30 11:44:42 +01:00
Sergio Garciaandpedrooot bc308de571 feat(SecurityHub): add test_connection method (#5350)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
2024-10-30 10:02:13 +01:00
Hugo Pereira BritoandSergio 4bee4d482a feat(s3): add new check s3_bucket_event_notifications_enabled (#5562)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-29 15:38:38 -05:00
82ec3e8779 feat(s3): add new check s3_multi_region_access_point_public_access_block (#5552)
Co-authored-by: Sergio <sergio@prowler.com>
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-29 14:56:56 -05:00
sansns-awsandSergio 85777546e8 feat(autoscaling): Add autoscaling_group_capacity_rebalance_enabled check (#5523)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-29 14:51:21 -05:00
Kay Agahd ec69d8073a fix(aws): findings in IAM policies were not reported (#5560) 2024-10-29 14:29:29 -05:00
Sergio Garcia e6053ce218 feat(slack): add test_connection method (#5340) 2024-10-29 18:14:06 +01:00
Sergio Garcia f01910e4f2 feat(gcp): add --organization-id flag (#5524) 2024-10-29 18:11:53 +01:00
sansns-aws 8848cadc0a chore(aws): Cleanup RDS and S3 tests (#5569) 2024-10-29 12:06:12 -05:00
sansns-aws 2c7d71a0d9 chore(glue): Cleanup tests (#5568) 2024-10-29 12:06:03 -05:00
sansns-aws dcd1b1121a chore(codebuild): Cleanup tests (#5567) 2024-10-29 11:31:19 -05:00
Hugo Pereira BritoandSergio 8a6e222f7a feat(wafv2): set us-east-1 region for global acls (#5558)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-29 10:16:48 -05:00
Prowler Botandsergargar a4c39c25f1 chore(regions_update): Changes in regions for AWS services (#5559)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-29 08:55:45 -05:00
Rubén De la Torre Vico 628d50cf0d chore(azure): deprecate AzureGermanCloud (#5561) 2024-10-29 08:54:55 -05:00
sansns-aws f70e3deade feat(aws): add DirectConnect service and checks (#5522) 2024-10-28 16:48:22 -05:00
sansns-aws 14f06d6497 chore(elbv2): cleanup tests (#5553) 2024-10-28 15:45:01 -05:00
Sergio Garcia 3c6e06837c fix(dependabot): security update werkzeug (#5551) 2024-10-28 13:49:47 -05:00
Sergio Garcia e778444d1d fix(PyPi): solve detect-secrets dependency (#5514) 2024-10-28 11:36:19 -05:00
NIRBHAY KUMARandSergio a4cca188ef chore(slack): add text argument by best practice (#5541)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-28 11:19:05 -05:00
Hugo Pereira Brito 76ee608ef8 fix: added s3 origin comprobation in cloudfront_distributions_s3_origin_non_existent_bucket (#5543) 2024-10-28 10:01:03 -05:00
Prowler Botandsergargar 7af5c82371 chore(regions_update): Changes in regions for AWS services (#5540)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-28 15:16:51 +01:00
172530153c feat(color): add --no-color flag (#5368)
Co-authored-by: pedrooot <pedromarting3@gmail.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-10-28 12:23:21 +01:00
Pedro Martín 0114d0462f feat(check): add check methods (#5462) 2024-10-28 12:22:34 +01:00
Pepe Fagoaga 6502330512 chore(providers): Remove get_output_mapping (#5484) 2024-10-28 11:40:31 +01:00
Prowler Botandsergargar 9bf9ebe4fd chore(regions_update): Changes in regions for AWS services (#5542)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-28 11:17:35 +01:00
Sergio Garcia 406d5864ee fix(kubernetes): handle input kube config file (#5502) 2024-10-28 08:51:37 +01:00
Sergio Garcia 0f9ebecbb7 fix(aws): review checks with wrong attributes (#5503) 2024-10-28 08:45:03 +01:00
Hugo Pereira BritoandSergio 0331af02ac feat(mq): add new check mq_broker_logging_enabled (#5483)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-25 14:33:35 -07:00
Sergio Garcia 64fb823276 fix(aws): review checks in compliance frameworks (#5513) 2024-10-25 18:32:46 +02:00
Prowler Botandsergargar 33f2c80a78 chore(regions_update): Changes in regions for AWS services (#5533)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-25 09:07:51 -07:00
dependabot[bot] 84ce7a8b52 chore(deps): bump trufflesecurity/trufflehog from 3.82.12 to 3.82.13 (#5531)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-24 16:13:42 -07:00
Hugo Pereira BritoandSergio 1a6b2eaa7d feat(mq): add new check mq_broker_active_deployment_mode (#5433)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-24 16:13:11 -07:00
Hugo Pereira BritoandSergio df373279e9 feat(mq): add new check mq_broker_cluster_deployment_mode (#5481)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-24 12:00:13 -07:00
Prowler Botandsergargar 6a09171851 chore(regions_update): Changes in regions for AWS services (#5519)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-24 07:54:54 -07:00
sansns-awsandSergio 93d257941b feat(aws): add new check fsx_windows_file_system_multi_az (#5491)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-23 14:07:57 -07:00
sansns-awsandSergio 28f8915f6f feat(aws): Add Fault Tolerance Checks (#5488)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-23 14:07:43 -07:00
Daniel BarranqueroandSergio fef99fd5fb feat(backup): add new check backup_recovery_point_encrypted (#5426)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-23 11:16:43 -07:00
sansns-awsandSergio 1e1c7cc1ce feat(aws): add new check redshift_cluster_multi_az_enabled (#5492)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-23 10:32:25 -07:00
sansns-awsandSergio 7e7d86f14a feat(aws): add new check dynamodb_accelerator_cluster_multi_az (#5493)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-23 10:16:56 -07:00
Prowler Botandsergargar 41cdc2bcc7 chore(regions_update): Changes in regions for AWS services (#5511)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-23 07:55:04 -07:00
dependabot[bot] c41866db38 chore(deps): bump trufflesecurity/trufflehog from 3.82.11 to 3.82.12 (#5508)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-22 16:27:05 -07:00
Mario Rodriguez LopezandSergio f36d23c9a7 feat(elb): add new check elb_desync_mitigation_mode (#5500)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-22 11:08:13 -07:00
Hugo Pereira BritoandSergio 8ac28fbcfd feat(waf): add new check waf_global_webacl_with_rules (#5469)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-22 10:26:22 -07:00
Hugo Pereira BritoandSergio 7f41ae7385 feat(waf): add new check waf_global_webacl_logging_enabled (#5479)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-22 09:41:00 -07:00
Prowler Botandsergargar 4c5f3a212c chore(regions_update): Changes in regions for AWS services (#5499)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-22 07:54:22 -07:00
Hugo Pereira BritoandSergio ffa29f2f6e feat(waf): add new check waf_global_rulegroup_not_empty (#5467)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-21 12:53:06 -07:00
Rubén De la Torre Vico 2ef9e27ee3 fix(kinesis): add missing init file (#5490) 2024-10-21 10:26:36 -07:00
Mario Rodriguez LopezandSergio d4b93d79b5 feat(elb): add new check elb_ssl_listeners_use_acm_certificate (#5424)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-21 10:15:12 -07:00
Daniel BarranqueroandSergio d00afbdc87 feat(apigateway): add new check apigateway_restapi_tracing_enabled (#5470)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-21 10:14:38 -07:00
Hugo Pereira BritoandSergio 5b0868e26c feat(waf): add new check waf_global_rule_with_conditions (#5465)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-21 10:14:15 -07:00
Mario Rodriguez LopezandSergio 415c319208 feat(iam): add new check iam_policy_cloudshell_admin_not_attached (#5437)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-21 07:41:58 -07:00
Daniel Barranquero 1aca7a754c feat(apigateway): add new check apigateway_restapi_cache_encrypted (#5448) 2024-10-21 07:38:55 -07:00
Prowler Botandsergargar 147c3c455b chore(regions_update): Changes in regions for AWS services (#5477)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-21 07:29:06 -07:00
Rubén De la Torre Vico d997ebb2cc feat(athena): add new check athena_workgroup_logging_enabled (#5468) 2024-10-18 16:40:57 -04:00
Mario Rodriguez Lopez 50cb79ee2f feat(aws): Add new checks ses_identities/glue_data_catalogs/secretsmanager _not_publicly_accessible (#5471) 2024-10-18 16:40:12 -04:00
johannes-engler-mwandSergio Garcia 2b34fd39f6 feat(containerregistry): add new check containerregistry_uses_private_link (#5375)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-18 16:15:52 -04:00
Mario Rodriguez LopezandSergio Garcia 0c82137834 feat(eventbridge): add new check eventbridge_global_endpoint_event_replication_enabled (#5396)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-18 15:36:39 -04:00
Hugo Pereira Brito 413b86e7cf chore(wafv2): migrated testing from magicmock to moto (#5464) 2024-10-18 14:55:49 -04:00
Pepe Fagoaga 23a20a582e chore(findings): add new properties (#5463) 2024-10-18 13:36:41 +02:00
Pepe Fagoaga 8411fcb5fc chore(severities): Use enum (#5460) 2024-10-18 11:39:48 +02:00
Pedro MartínandPepe Fagoaga 41e585643b feat(scan): add mutelist and config file to scan (#5310)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-10-18 10:34:46 +02:00
dependabot[bot] aca5824240 chore(deps): bump trufflesecurity/trufflehog from 3.82.9 to 3.82.11 (#5458)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-18 09:29:38 +02:00
Pedro Martín e65b346afd feat(exceptions): modify custom exceptions (#5451) 2024-10-18 09:28:58 +02:00
Pepe Fagoagaanddependabot[bot] 98cb954f74 refactor(finding): Add metadata object (#5447)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-18 09:26:50 +02:00
Hugo Pereira BritoandRubén De la Torre Vico 778edd5fec feat(mq): add new check mq_broker_auto_minor_version_upgrades (#5431)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-10-17 14:33:42 -04:00
Rubén De la Torre Vico 06deda7e5f feat(opensearch): add new check opensearch_domain_master_nodes_fault_tolerant (#5393) 2024-10-17 14:32:42 -04:00
Adrián Jesús Peña Rodríguez 26a00a14df feat(datasync): add datasync service and check datasync_task_logging_enabled (#5444) 2024-10-17 13:07:18 -04:00
Sergio Garcia 12abea371d fix(bedrock): add filtering and handle different ARNs (#5453) 2024-10-17 12:53:18 -04:00
Rubén De la Torre Vico a17cf1bbb6 feat(secretsmanager): add new check secretsmanager_secret_unused (#5428) 2024-10-17 10:24:12 -04:00
Mario Rodriguez LopezandSergio Garcia 5d51942768 feat(fsx): add new check fsx_file_system_copy_tags_to_backups_enabled (#5417)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-17 10:23:21 -04:00
Pepe Fagoaga 3122d727a5 chore(aws): Add AWSSessionTokenExpired (#5378) 2024-10-17 15:43:27 +02:00
Mario Rodriguez LopezandSergio Garcia e5f89d5bc7 feat(fsx): add new check fsx_file_system_copy_tags_to_volumes_enabled (#5414)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-17 09:40:42 -04:00
Pedro Martín efc60d2bf4 feat(scan): add status argument (#5443) 2024-10-17 15:27:27 +02:00
Mario Rodriguez Lopez f7fd355dc1 refactor(acm): Change certificates from list to dict in acm_service (#5420) 2024-10-17 09:16:21 -04:00
Prowler Botandsergargar 7bd402bf4e chore(regions_update): Changes in regions for AWS services (#5445)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-17 08:49:42 -04:00
Pedro Martín b69962efb6 feat(scan): add excluded_checks and services (#5442) 2024-10-17 10:25:07 +02:00
2b8b223403 feat(k8s): Add kubeconfig content authentication (#5397)
Co-authored-by: Sergio <sergio@prowler.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-10-17 09:56:51 +02:00
Pedro Martín a024ab31a0 feat(scan): add arguments (#5427) 2024-10-17 09:29:02 +02:00
Hugo Pereira BritoandSergio 9969e271ed feat(waf): add new check waf_regional_rulegroup_not_empty (#5415)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-16 15:22:24 -04:00
Sergio GarciaandPepe Fagoaga f1449b66d6 feat(k8s): Add kubeconfig content static authentication (#5370)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-10-16 18:52:15 +02:00
Hugo Pereira BritoandSergio 3c0f360244 feat(waf): add new check waf_regional_rule_with_conditions (#5411)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-16 12:41:57 -04:00
Sergio Garcia 6e3c008a89 chore(aws): improve logic for determining if resources are publicly accessible (#5195) 2024-10-16 12:10:38 -04:00
Hugo Pereira BritoandSergio Garcia 9d97b1a7ee feat(waf): add new check waf_regional_webacl_with_rules (#5392)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-16 11:58:03 -04:00
Hugo Pereira BritoandSergio Garcia d07f1e982a feat(wafv2): add new check wafv2_webacl_with_rules (#5376)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-16 11:44:41 -04:00
Hugo Pereira BritoandSergio 402e0e3107 feat(wafv2): add new check wafv2_webacl_rule_logging_enabled (#5362)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-16 10:19:19 -04:00
dependabot[bot] c5716bf9b6 chore(deps): bump trufflesecurity/trufflehog from 3.82.8 to 3.82.9 (#5421)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-16 09:03:57 -04:00
Pepe Fagoaga bfdff563e6 chore(aws): Set scan_unused_services False by default (#5425) 2024-10-16 13:19:10 +02:00
Pedro MartínandPepe Fagoaga 4be83f240a feat(azure): add provider id validation inside test_connection (#5391)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-10-16 12:02:40 +02:00
Daniel BarranqueroandSergio 45c32abcdf feat(autoscaling): add new check autoscaling_group_multiple_instance_types (#5325)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-15 15:36:48 -04:00
Hugo Pereira Brito c0ac4c7c30 feat(MQ): add new service MQ (#5419) 2024-10-15 14:32:28 -04:00
Daniel BarranqueroandSergio c90cb3712b feat(cloudwatch): add new check cloudwatch_alarm_actions_alarm_state_configured (#5404)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-15 10:51:02 -04:00
Daniel BarranqueroandSergio 23c3884ab7 feat(cloudwatch): add new check cloudwatch_alarm_actions_enabled (#5416)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-15 09:50:50 -04:00
Mario Rodriguez LopezandSergio a491e39a18 feat(fsx): Add new service FSx (#5412)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-15 09:01:25 -04:00
78d2fb9fd5 feat(codebuild): add new check codebuild_report_group_export_encrypted (#5384)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-15 08:39:18 -04:00
Rubén De la Torre VicoandSergio Garcia aac6038565 feat(codebuild): add new check codebuild_project_logging_enabled (#5365)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-15 07:42:45 -04:00
Prowler Botandsergargar 0449d6372c chore(regions_update): Changes in regions for AWS services (#5413)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-15 07:41:07 -04:00
Pedro Martín bc1e6c0626 feat(azure): add authentication method from static credentials (#5358) 2024-10-15 09:37:17 +02:00
Pedro Martín c1d061ef70 feat(gcp): add provider id validation inside test_connection (#5381) 2024-10-15 09:04:17 +02:00
Mario Rodriguez LopezandSergio 9788fe4236 feat(macie): add new check macie_automated_sensitive_data_discovery_enabled (#5390)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-14 17:58:44 -04:00
Mario Rodriguez LopezandSergio 7fd0798b7c feat(opensearch): add new check opensearch_service_domains_fault_tolerant_data_nodes (#5366)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-14 14:49:46 -04:00
Rubén De la Torre VicoandSergio 82ab439e9a feat(codebuild): add new check codebuild_project_s3_logs_encrypted (#5363)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-14 14:40:04 -04:00
Sergio Garcia 54280ee2dc fix(iam): update AWS Support policy (#5399) 2024-10-14 13:58:42 -04:00
Sergio Garcia 434460b978 fix(organizations): no finding for access denied in listing policies (#5400) 2024-10-14 13:58:30 -04:00
Daniel BarranqueroandSergio 808fa96407 feat(autoscaling): add new check autoscaling_group_launch_configuration_requires_imdsv2 (#5356)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-14 13:16:02 -04:00
Hugo Pereira BritoandSergio 2c0c1f7d09 refactor(WAF): Rename WAF to WAFRegional and Add Global WAF Service (#5389)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-14 11:49:26 -04:00
Rubén De la Torre Vico 037e40f8e4 feat(config): add new check config_recorder_using_aws_service_role (#5357) 2024-10-14 11:19:35 -04:00
Daniel Barranquero e0ed891fc4 feat(autoscaling): add new check autoscaling_group_launch_configuration_no_public_ip (#5359) 2024-10-14 11:17:36 -04:00
Daniel BarranqueroandSergio Garcia dfc8e3e38f feat(autoscaling): add new check autoscaling_group_using_ec2_launch_template (#5346)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-14 10:55:19 -04:00
Sergio Garcia aef4a68c46 feat(bedrock): add checks for guardrails configuration and log encryption (#5385) 2024-10-14 10:49:58 -04:00
Sergio Garcia 3c929bd68f feat(aws): add checks for Bedrock logging configuration and CloudTrail LLM Jacking detection (#5314) 2024-10-11 15:01:45 -04:00
JonnyandSergio Garcia 444d820f98 chore(lambda): update obsolete lambda runtime (#5379)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-11 12:05:04 -04:00
Hugo Pereira BritoandSergio 304bb27502 feat(waf): change WAF Classic web_acls from list to dict (#5380)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-11 11:05:37 -04:00
Mario Rodriguez LopezandSergio a6db526eec feat(elasticbeanstalk): add new check elasticbeanstalk_enhanced_health_reporting_enabled (#5348)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-11 10:27:48 -04:00
Sergio Garcia 3ace44979a chore(aws): add more cases to public IAM resource policies (#5336) 2024-10-11 10:27:23 -04:00
Prowler Botandsergargar 493d6a9210 chore(regions_update): Changes in regions for AWS services (#5377)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-10-11 09:29:26 -04:00
dependabot[bot] 3762d70ba3 chore(deps): bump trufflesecurity/trufflehog from 3.82.7 to 3.82.8 (#5371)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-11 09:28:43 -04:00
Pedro Martín 03a26ec507 feat(gcp): add static credentials for gcp provider (#5364) 2024-10-11 11:01:37 +02:00
Mario Rodriguez LopezandSergio c3e3381c63 feat(elasticbeanstalk): add new check elasticbeanstalk_cloudwatch_enabled (#5335)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-10 15:32:31 -04:00
Mario Rodriguez LopezandSergio f8a8266c9d feat(elasticbeanstalk): add new check elasticbeanstalk_managed_platform_updates_enabled (#5324)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-10 15:31:11 -04:00
Pepe Fagoaga d9c2933dc5 feat(test_connection): Add optional AWS Account ID validation (#5361) 2024-10-10 12:45:16 -04:00
Pepe Fagoaga cad99c5e0f feat(aws): Add static credentials authentication (#5360) 2024-10-10 11:47:05 -04:00
johannes-engler-mwandRubén De la Torre Vico 9f2de7d2f9 feat(containerregistry): add new check containerregistry_not_publicly_accessible (#5291)
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
2024-10-10 11:39:16 -04:00
Daniel BarranqueroandSergio 4181ca56be feat(autoscaling): add new check autoscaling_group_elb_health_check_enabled (#5330)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-09 14:56:18 -04:00
Daniel BarranqueroandSergio Garcia d45750b042 feat(redshift): add new check redshift_cluster_enhanced_vpc_routing (#5281)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-10-09 12:40:36 -04:00
Mario Rodriguez LopezandSergio 16191a7b15 feat(elasticbeanstalk): Add new service ElasticBeanstalk (#5322)
Co-authored-by: Sergio <sergio@prowler.com>
2024-10-09 09:29:19 -04:00
Rubén De la Torre Vico 0c149461b3 chore(sns): manage ResourceNotFoundException and add paralelism (#5345) 2024-10-09 08:56:39 -04:00
Pedro Martín 3ee39cff2a feat(scan): execute all checks if no checks are provided (#5307) 2024-10-09 11:46:38 +02:00
41ba118cc4 feat(scan): add scan duration (#5305)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
Co-authored-by: Sergio <sergio@prowler.com>
Co-authored-by: Prowler Bot <bot@prowler.com>
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com>
2024-10-09 11:12:39 +02:00
1029 changed files with 68279 additions and 10100 deletions

No files matched your search

+43 -2
View File
@@ -5,6 +5,7 @@
version: 2
updates:
# v5
- package-ecosystem: "pip"
directory: "/"
schedule:
@@ -14,29 +15,69 @@ updates:
labels:
- "dependencies"
- "pip"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
target-branch: master
labels:
- "dependencies"
- "github_actions"
- package-ecosystem: "pip"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
target-branch: master
labels:
- "dependencies"
- "npm"
# v4.6
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: v4.6
labels:
- "dependencies"
- "pip"
- "v4"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: v4.6
labels:
- "dependencies"
- "github_actions"
- "v4"
# v3
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
target-branch: v3
labels:
- "dependencies"
- "pip"
- "v3"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "monthly"
open-pull-requests-limit: 10
target-branch: v3
labels:
- "dependencies"
- "github_actions"
- "v3"
+7
View File
@@ -79,3 +79,10 @@ output/csv:
- changed-files:
- any-glob-to-any-file: "prowler/lib/outputs/csv/**"
- any-glob-to-any-file: "tests/lib/outputs/csv/**"
compliance:
- changed-files:
- any-glob-to-any-file: "prowler/lib/outputs/compliance/**"
- any-glob-to-any-file: "tests/lib/outputs/compliance/**"
- any-glob-to-any-file: "prowler/compliance/**"
@@ -3,7 +3,11 @@ name: build-lint-push-containers
on:
push:
branches:
# For `v3-latest`
- "v3"
# For `v4-latest`
- "v4.6"
# For `latest`
- "master"
paths-ignore:
- ".github/**"
@@ -58,7 +62,7 @@ jobs:
- name: Install Poetry
run: |
pipx install poetry
pipx install poetry==1.8.5
pipx inject poetry poetry-bumpversion
- name: Get Prowler version
@@ -80,8 +84,8 @@ jobs:
;;
4)
echo "LATEST_TAG=latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=stable" >> "${GITHUB_ENV}"
echo "LATEST_TAG=v4-latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=v4-stable" >> "${GITHUB_ENV}"
;;
*)
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@v3.82.7
uses: trufflesecurity/trufflehog@v3.88.18
with:
path: ./
base: ${{ github.event.repository.default_branch }}
+3 -3
View File
@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v4
- name: Test if changes are in not ignored paths
id: are-non-ignored-files-changed
uses: tj-actions/changed-files@v45
uses: tj-actions/changed-files@v46
with:
files: ./**
files_ignore: |
@@ -36,7 +36,7 @@ jobs:
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
run: |
python -m pip install --upgrade pip
pipx install poetry
pipx install poetry==1.8.5
- name: Set up Python ${{ matrix.python-version }}
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: actions/setup-python@v5
@@ -91,6 +91,6 @@ jobs:
poetry run pytest -n auto --cov=./prowler --cov-report=xml tests
- name: Upload coverage reports to Codecov
if: steps.are-non-ignored-files-changed.outputs.any_changed == 'true'
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
- name: Install dependencies
run: |
pipx install poetry
pipx install poetry==1.8.5
- name: Setup Python
uses: actions/setup-python@v5
+1 -1
View File
@@ -85,7 +85,7 @@ repos:
# For running trufflehog in docker, use the following entry instead:
# entry: bash -c 'docker run -v "$(pwd):/workdir" -i --rm trufflesecurity/trufflehog:latest git file:///workdir --only-verified --fail'
language: system
stages: ["commit", "push"]
stages: ["pre-commit", "pre-push"]
- id: bandit
name: bandit
+2 -2
View File
@@ -1,4 +1,4 @@
FROM python:3.12-alpine
FROM python:3.12.9-alpine3.20
LABEL maintainer="https://github.com/prowler-cloud/prowler"
@@ -6,7 +6,7 @@ LABEL maintainer="https://github.com/prowler-cloud/prowler"
#hadolint ignore=DL3018
RUN apk --no-cache upgrade && apk --no-cache add curl git
# Create nonroot user
# Create non-root user
RUN mkdir -p /home/prowler && \
echo 'prowler:x:1000:1000:prowler:/home/prowler:' > /etc/passwd && \
echo 'prowler:x:1000:' > /etc/group && \
+6 -6
View File
@@ -10,13 +10,13 @@
</p>
<p align="center">
<a href="https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog"><img width="30" height="30" alt="Prowler community on Slack" src="https://github.com/prowler-cloud/prowler/assets/38561120/3c8b4ec5-6849-41a5-b5e1-52bbb94af73a"></a>
<a href="https://goto.prowler.com/slack"><img width="30" height="30" alt="Prowler community on Slack" src="https://github.com/prowler-cloud/prowler/assets/38561120/3c8b4ec5-6849-41a5-b5e1-52bbb94af73a"></a>
<br>
<a href="https://join.slack.com/t/prowler-workspace/shared_invite/zt-2oinmgmw6-cl7gOrljSEqo_aoripVPFA">Join our Prowler community!</a>
<a href="https://goto.prowler.com/slack">Join our Prowler community!</a>
</p>
<hr>
<p align="center">
<a href="https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog"><img alt="Slack Shield" src="https://img.shields.io/badge/slack-prowler-brightgreen.svg?logo=slack"></a>
<a href="https://goto.prowler.com/slack"><img alt="Slack Shield" src="https://img.shields.io/badge/slack-prowler-brightgreen.svg?logo=slack"></a>
<a href="https://pypi.org/project/prowler/"><img alt="Python Version" src="https://img.shields.io/pypi/v/prowler.svg"></a>
<a href="https://pypi.python.org/pypi/prowler/"><img alt="Python Version" src="https://img.shields.io/pypi/pyversions/prowler.svg"></a>
<a href="https://pypistats.org/packages/prowler"><img alt="PyPI Prowler Downloads" src="https://img.shields.io/pypi/dw/prowler.svg?label=prowler%20downloads"></a>
@@ -63,9 +63,9 @@ It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, Fe
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) |
|---|---|---|---|---|
| AWS | 457 | 67 -> `prowler aws --list-services` | 30 -> `prowler aws --list-compliance` | 9 -> `prowler aws --list-categories` |
| GCP | 77 | 13 -> `prowler gcp --list-services` | 2 -> `prowler gcp --list-compliance` | 2 -> `prowler gcp --list-categories`|
| Azure | 136 | 17 -> `prowler azure --list-services` | 3 -> `prowler azure --list-compliance` | 2 -> `prowler azure --list-categories` |
| AWS | 553 | 77 -> `prowler aws --list-services` | 30 -> `prowler aws --list-compliance` | 9 -> `prowler aws --list-categories` |
| GCP | 77 | 13 -> `prowler gcp --list-services` | 3 -> `prowler gcp --list-compliance` | 2 -> `prowler gcp --list-categories`|
| Azure | 138 | 17 -> `prowler azure --list-services` | 4 -> `prowler azure --list-compliance` | 2 -> `prowler azure --list-categories` |
| Kubernetes | 83 | 7 -> `prowler kubernetes --list-services` | 1 -> `prowler kubernetes --list-compliance` | 7 -> `prowler kubernetes --list-categories` |
# 💻 Installation
+36
View File
@@ -0,0 +1,36 @@
import warnings
from dashboard.common_methods import get_section_containers_ens
warnings.filterwarnings("ignore")
def get_table(data):
# append the requirements_description to idgrupocontrol
data["REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL"] = (
data["REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL"]
+ " - "
+ data["REQUIREMENTS_DESCRIPTION"]
)
aux = data[
[
"REQUIREMENTS_ATTRIBUTES_MARCO",
"REQUIREMENTS_ATTRIBUTES_CATEGORIA",
"REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL",
"REQUIREMENTS_ATTRIBUTES_TIPO",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_ens(
aux,
"REQUIREMENTS_ATTRIBUTES_MARCO",
"REQUIREMENTS_ATTRIBUTES_CATEGORIA",
"REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL",
"REQUIREMENTS_ATTRIBUTES_TIPO",
)
+36
View File
@@ -0,0 +1,36 @@
import warnings
from dashboard.common_methods import get_section_containers_ens
warnings.filterwarnings("ignore")
def get_table(data):
# append the requirements_description to idgrupocontrol
data["REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL"] = (
data["REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL"]
+ " - "
+ data["REQUIREMENTS_DESCRIPTION"]
)
aux = data[
[
"REQUIREMENTS_ATTRIBUTES_MARCO",
"REQUIREMENTS_ATTRIBUTES_CATEGORIA",
"REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL",
"REQUIREMENTS_ATTRIBUTES_TIPO",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_ens(
aux,
"REQUIREMENTS_ATTRIBUTES_MARCO",
"REQUIREMENTS_ATTRIBUTES_CATEGORIA",
"REQUIREMENTS_ATTRIBUTES_IDGRUPOCONTROL",
"REQUIREMENTS_ATTRIBUTES_TIPO",
)
+21 -9
View File
@@ -148,6 +148,7 @@ else:
select_account_dropdown_list = ["All"]
# Append to the list the unique values of the columns ACCOUNTID, PROJECTID and SUBSCRIPTIONID if they exist
if "ACCOUNTID" in data.columns:
data["ACCOUNTID"] = data["ACCOUNTID"].astype(str)
select_account_dropdown_list = select_account_dropdown_list + list(
data["ACCOUNTID"].unique()
)
@@ -246,9 +247,11 @@ def display_data(
dfs = []
for file in files:
df = pd.read_csv(
file, sep=";", on_bad_lines="skip", encoding=encoding_format
file, sep=";", on_bad_lines="skip", encoding=encoding_format, dtype=str
)
dfs.append(df.astype(str))
df = df.astype(str).fillna("nan")
df.columns = df.columns.astype(str)
dfs.append(df)
return pd.concat(dfs, ignore_index=True)
data = load_csv_files(files)
@@ -274,17 +277,24 @@ def display_data(
data.rename(columns={"PROJECTID": "ACCOUNTID"}, inplace=True)
data["REGION"] = "-"
# Rename the column SUBSCRIPTIONID to ACCOUNTID for Azure
if data.columns.str.contains("SUBSCRIPTIONID").any():
if (
data.columns.str.contains("SUBSCRIPTIONID").any()
and not data.columns.str.contains("ACCOUNTID").any()
):
data.rename(columns={"SUBSCRIPTIONID": "ACCOUNTID"}, inplace=True)
data["REGION"] = "-"
# Handle v3 azure cis compliance
if data.columns.str.contains("SUBSCRIPTION").any():
if (
data.columns.str.contains("SUBSCRIPTION").any()
and not data.columns.str.contains("ACCOUNTID").any()
):
data.rename(columns={"SUBSCRIPTION": "ACCOUNTID"}, inplace=True)
data["REGION"] = "-"
# Filter ACCOUNT
if account_filter == ["All"]:
updated_cloud_account_values = data["ACCOUNTID"].unique()
elif "All" in account_filter and len(account_filter) > 1:
# Remove 'All' from the list
account_filter.remove("All")
@@ -299,9 +309,11 @@ def display_data(
account_filter_options = list(data["ACCOUNTID"].unique())
account_filter_options = account_filter_options + ["All"]
for item in account_filter_options:
if "nan" in item or item.__class__.__name__ != "str" or item is None:
account_filter_options.remove(item)
account_filter_options = [
item
for item in account_filter_options
if isinstance(item, str) and item.lower() != "nan"
]
# Filter REGION
if region_filter_analytics == ["All"]:
@@ -520,8 +532,8 @@ def get_bar_graph(df, column_name):
# Cut the text if it is too long
for i in range(len(colums)):
if len(colums[i]) > 15:
colums[i] = colums[i][:15] + "..."
if len(colums[i]) > 43:
colums[i] = colums[i][:43] + "..."
fig = px.bar(
df,
+1 -1
View File
@@ -2,7 +2,7 @@
For technical support or any type of inquiries, you are very welcome to:
- Reach out to community members on the [**Prowler Slack channel**](https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog)
- Reach out to community members on the [**Prowler Slack channel**](https://goto.prowler.com/slack)
- Open an Issue or a Pull Request in our [**GitHub repository**](https://github.com/prowler-cloud/prowler).
+14 -8
View File
@@ -160,14 +160,20 @@ else:
All the checks MUST fill the `report.resource_id` and `report.resource_arn` with the following criteria:
- AWS
- Resource ID -- `report.resource_id`
- AWS Account --> Account Number `123456789012`
- AWS Resource --> Resource ID / Name
- Root resource --> `<root_account>`
- Resource ARN -- `report.resource_arn`
- AWS Account --> Root ARN `arn:aws:iam::123456789012:root`
- AWS Resource --> Resource ARN
- Root resource --> Resource Type ARN `f"arn:{service_client.audited_partition}:<service_name>:{service_client.region}:{service_client.audited_account}:<resource_type>"`
- Resouce ID and resource ARN:
- If the resource audited is the AWS account:
- `resource_id` -> AWS Account Number
- `resource_arn` -> AWS Account Root ARN
- If we can’t get the ARN from the resource audited, we create a valid ARN with the `resource_id` part as the resource audited. Examples:
- Bedrock -> `arn:<partition>:bedrock:<region>:<account-id>:model-invocation-logging`
- DirectConnect -> `arn:<partition>:directconnect:<region>:<account-id>:dxcon`
- If there is no real resource to audit we do the following:
- resource_id -> `resource_type/unknown`
- resource_arn -> `arn:<partition>:<service>:<region>:<account-id>:<resource_type>/unknown`
- Examples:
- AWS Security Hub -> `arn:<partition>:security-hub:<region>:<account-id>:hub/unknown`
- Access Analyzer -> `arn:<partition>:access-analyzer:<region>:<account-id>:analyzer/unknown`
- GuardDuty -> `arn:<partition>:guardduty:<region>:<account-id>:detector/unknown`
- GCP
- Resource ID -- `report.resource_id`
- GCP Resource --> Resource ID
+1 -1
View File
@@ -67,4 +67,4 @@ If you create or review a PR in https://github.com/prowler-cloud/prowler please
## Want some swag as appreciation for your contribution?
If you are like us and you love swag, we are happy to thank you for your contribution with some laptop stickers or whatever other swag we may have at that time. Please, tell us more details and your pull request link in our [Slack workspace here](https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog). You can also reach out to Toni de la Fuente on Twitter [here](https://twitter.com/ToniBlyx), his DMs are open.
If you are like us and you love swag, we are happy to thank you for your contribution with some laptop stickers or whatever other swag we may have at that time. Please, tell us more details and your pull request link in our [Slack workspace here](https://goto.prowler.com/slack). You can also reach out to Toni de la Fuente on Twitter [here](https://twitter.com/ToniBlyx), his DMs are open.
+9 -19
View File
@@ -44,7 +44,6 @@ class Provider(ABC):
Methods:
print_credentials(): Displays the provider's credentials used for auditing in the command-line interface.
setup_session(): Sets up the session for the provider.
get_output_mapping(): Returns the output mapping between the provider and the generic model.
validate_arguments(): Validates the arguments for the provider.
get_checks_to_execute_by_audit_resources(): Returns a set of checks based on the input resources to scan.
@@ -131,15 +130,6 @@ class Provider(ABC):
"""
raise NotImplementedError()
@abstractmethod
def get_output_mapping(self) -> dict:
"""
get_output_mapping returns the output mapping between the provider and the generic model.
This method needs to be created in each provider.
"""
raise NotImplementedError()
def validate_arguments(self) -> None:
"""
validate_arguments validates the arguments for the provider.
@@ -200,18 +190,18 @@ from prowler.providers.common.models import Audit_Metadata
from prowler.providers.common.provider import Provider
from prowler.providers.<new_provider_name>.models import (
# All providers models needed
ProvierSessionModel,
ProvierIdentityModel,
ProvierOutputOptionsModel
ProviderSessionModel,
ProviderIdentityModel,
ProviderOutputOptionsModel
)
class NewProvider(Provider):
# All properties from the class, some of this are properties in the base class
_type: str = "<provider_name>"
_session: <ProvierSessionModel>
_identity: <ProvierIdentityModel>
_session: <ProviderSessionModel>
_identity: <ProviderIdentityModel>
_audit_config: dict
_output_options: ProvierOutputOptionsModel
_output_options: ProviderOutputOptionsModel
_mutelist: dict
audit_metadata: Audit_Metadata
@@ -222,13 +212,13 @@ class NewProvider(Provider):
arguments (dict): A dictionary containing configuration arguments.
"""
logger.info("Setting <NewProviderName> provider ...")
# First get from arguments the necesary from the cloud acount (subscriptions or projects or whatever the provider use for storing services)
# First get from arguments the necessary from the cloud account (subscriptions or projects or whatever the provider use for storing services)
# Set the session with the method enforced by parent class
self._session = self.setup_session(credentials_file)
# Set the Identity class normaly the provider class give by Python provider library
self._identity = <ProvierIdentityModel>()
self._identity = <ProviderIdentityModel>()
# Set the provider configuration
self._audit_config = load_and_validate_config_file(
@@ -264,7 +254,7 @@ class NewProvider(Provider):
<all_needed_for_auth> Can include all necessary arguments to setup the session
Returns:
Credentials necesary to communicate with the provider.
Credentials necessary to communicate with the provider.
"""
pass
+11 -7
View File
@@ -4,21 +4,25 @@ Prowler allows you to do threat detection in AWS based on the CloudTrail log rec
```
prowler aws --category threat-detection
```
This comand will run these checks:
This command will run these checks:
* `cloudtrail_threat_detection_privilege_escalation`
* `cloudtrail_threat_detection_enumeration`
* `cloudtrail_threat_detection_privilege_escalation` -> Detects privilege escalation attacks.
* `cloudtrail_threat_detection_enumeration` -> Detects enumeration attacks.
* `cloudtrail_threat_detection_llm_jacking` -> Detects LLM Jacking attacks.
???+ note
Threat Detection checks will be only executed using `--category threat-detection` flag due to preformance.
Threat Detection checks will be only executed using `--category threat-detection` flag due to performance.
## Config File
If you want to manage the behavior of the Threat Detection checks you can edit `config.yaml` file from `/prowler/config`. In this file you can edit the following attributes related with Threat Detection:
* `threat_detection_privilege_escalation_threshold`: determines the percentage of actions found to decide if it is an privilege_scalation attack event, by default is 0.1 (10%)
* `threat_detection_privilege_escalation_threshold`: determines the percentage of actions found to decide if it is an privilege_scalation attack event, by default is 0.2 (20%)
* `threat_detection_privilege_escalation_minutes`: it is the past minutes to search from now for privilege_escalation attacks, by default is 1440 minutes (24 hours)
* `threat_detection_privilege_escalation_actions`: these are the default actions related with priviledge scalation.
* `threat_detection_enumeration_threshold`: determines the percentage of actions found to decide if it is an enumeration attack event, by default is 0.1 (10%)
* `threat_detection_privilege_escalation_actions`: these are the default actions related with privilege escalation.
* `threat_detection_enumeration_threshold`: determines the percentage of actions found to decide if it is an enumeration attack event, by default is 0.3 (30%)
* `threat_detection_enumeration_minutes`: it is the past minutes to search from now for enumeration attacks, by default is 1440 minutes (24 hours)
* `threat_detection_enumeration_actions`: these are the default actions related with enumeration attacks.
* `threat_detection_llm_jacking_threshold`: determines the percentage of actions found to decide if it is an LLM Jacking attack event, by default is 0.4 (40%)
* `threat_detection_llm_jacking_minutes`: it is the past minutes to search from now for LLM Jacking attacks, by default is 1440 minutes (24 hours)
* `threat_detection_llm_jacking_actions`: these are the default actions related with LLM Jacking attacks.
@@ -7,7 +7,6 @@ At the time of writing this documentation the available Azure Clouds from differ
- AzureCloud
- AzureChinaCloud
- AzureUSGovernment
- AzureGermanCloud
If you want to change the default one you must include the flag `--azure-region`, i.e.:
+23 -2
View File
@@ -47,6 +47,7 @@ The following list includes all the AWS checks with configurable variables that
| `ecr_repositories_scan_vulnerabilities_in_latest_image` | `ecr_repository_vulnerability_minimum_severity` | String |
| `eks_cluster_uses_a_supported_version` | `eks_cluster_oldest_version_supported` | String |
| `eks_control_plane_logging_all_types_enabled` | `eks_required_log_types` | List of Strings |
| `elasticache_redis_cluster_backup_enabled` | `minimum_snapshot_retention_period` | Integer |
| `elb_is_in_multiple_az` | `elb_min_azs` | Integer |
| `elbv2_is_in_multiple_az` | `elbv2_min_azs` | Integer |
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
@@ -56,6 +57,8 @@ The following list includes all the AWS checks with configurable variables that
| `organizations_scp_check_deny_regions` | `organizations_enabled_regions` | List of Strings |
| `rds_instance_backup_enabled` | `check_rds_instance_replicas` | Boolean |
| `securityhub_enabled` | `mute_non_default_regions` | Boolean |
| `secretsmanager_secret_unused` | `max_days_secret_unused` | Integer |
| `secretsmanager_secret_rotated_periodically` | `max_days_secret_unrotated` | Integer |
| `ssm_document_secrets` | `secrets_ignore_patterns` | List of Strings |
| `trustedadvisor_premium_support_plan_subscribed` | `verify_premium_support_plans` | Boolean |
| `vpc_endpoint_connections_trust_boundaries` | `trusted_account_ids` | List of Strings |
@@ -226,7 +229,7 @@ aws:
# AWS CloudTrail Configuration
# aws.cloudtrail_threat_detection_privilege_escalation
threat_detection_privilege_escalation_threshold: 0.1 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.1 (10%)
threat_detection_privilege_escalation_threshold: 0.2 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.2 (20%)
threat_detection_privilege_escalation_minutes: 1440 # Past minutes to search from now for privilege_escalation attacks, by default is 1440 minutes (24 hours)
threat_detection_privilege_escalation_actions:
[
@@ -283,7 +286,7 @@ aws:
"UpdateLoginProfile",
]
# aws.cloudtrail_threat_detection_enumeration
threat_detection_enumeration_threshold: 0.1 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.1 (10%)
threat_detection_enumeration_threshold: 0.3 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.3 (30%)
threat_detection_enumeration_minutes: 1440 # Past minutes to search from now for enumeration attacks, by default is 1440 minutes (24 hours)
threat_detection_enumeration_actions:
[
@@ -378,6 +381,24 @@ aws:
"LookupEvents",
"Search",
]
# aws.cloudtrail_threat_detection_llm_jacking
threat_detection_llm_jacking_threshold: 0.4 # Percentage of actions found to decide if it is an LLM Jacking attack event, by default is 0.4 (40%)
threat_detection_llm_jacking_minutes: 1440 # Past minutes to search from now for LLM Jacking attacks, by default is 1440 minutes (24 hours)
threat_detection_llm_jacking_actions:
[
"PutUseCaseForModelAccess", # Submits a use case for model access, providing justification (Write).
"PutFoundationModelEntitlement", # Grants entitlement for accessing a foundation model (Write).
"PutModelInvocationLoggingConfiguration", # Configures logging for model invocations (Write).
"CreateFoundationModelAgreement", # Creates a new agreement to use a foundation model (Write).
"InvokeModel", # Invokes a specified Bedrock model for inference using provided prompt and parameters (Read).
"InvokeModelWithResponseStream", # Invokes a Bedrock model for inference with real-time token streaming (Read).
"GetUseCaseForModelAccess", # Retrieves an existing use case for model access (Read).
"GetModelInvocationLoggingConfiguration", # Fetches the logging configuration for model invocations (Read).
"GetFoundationModelAvailability", # Checks the availability of a foundation model for use (Read).
"ListFoundationModelAgreementOffers", # Lists available agreement offers for accessing foundation models (List).
"ListFoundationModels", # Lists the available foundation models in Bedrock (List).
"ListProvisionedModelThroughputs", # Lists the provisioned throughput for previously created models (List).
]
# AWS RDS Configuration
# aws.rds_instance_backup_enabled
+22
View File
@@ -0,0 +1,22 @@
# GCP Organization
By default, Prowler scans all Google Cloud projects accessible to the authenticated user.
To limit the scan to projects within a specific Google Cloud organization, use the `--organization-id` option with the GCP organization ID:
```console
prowler gcp --organization-id organization-id
```
???+ warning
Make sure that the used credentials have the role Cloud Asset Viewer (`roles/cloudasset.viewer`) or Cloud Asset Owner (`roles/cloudasset.owner`) on the organization level.
???+ note
With this option, Prowler retrieves all projects within the specified organization, including those organized in folders and nested subfolders. This ensures that every project under the organization’s hierarchy is scanned, providing full visibility across the entire organization.
???+ note
To find the organization ID, use the following command:
```console
gcloud organizations list
```
+6 -1
View File
@@ -24,6 +24,11 @@ Prowler can run without showing its banner:
```console
prowler <provider> -b/--no-banner
```
## Disable Colors
Prowler can run without showing colors:
```console
prowler <provider> --no-color
```
## Checks
Prowler has checks per provider, there are options related with them:
@@ -120,5 +125,5 @@ prowler <provider> --list-categories
```
- Execute specific category(s):
```console
prowler <provider> --categories
prowler <provider> --categories secrets
```
+36
View File
@@ -0,0 +1,36 @@
# Prowler Check Kreator
???+ note
Currently, this tool is only available for creating checks for the AWS provider.
**Prowler Check Kreator** is a utility designed to streamline the creation of new checks for Prowler. This tool generates all necessary files required to add a new check to the Prowler repository. Specifically, it creates:
- A dedicated folder for the check.
- The main check script.
- A metadata file with essential details.
- A folder and file structure for testing the check.
## Usage
To use the tool, execute the main script with the following command:
```bash
python util/prowler_check_kreator/prowler_check_kreator.py <prowler_provider> <check_name>
```
Parameters:
- `<prowler_provider>`: Currently only AWS is supported.
- `<check_name>`: The name you wish to assign to the new check.
## AI integration
This tool optionally integrates AI to assist in generating the check code and metadata file content. When AI assistance is chosen, the tool uses [Gemini](https://gemini.google.com/) to produce preliminary code and metadata.
???+ note
For this feature to work, you must have the library `google-generativeai` installed in your Python environment.
???+ warning
AI-generated code and metadata might contain errors or require adjustments to align with specific Prowler requirements. Carefully review all AI-generated content before committing.
To enable AI assistance, simply confirm when prompted by the tool. Additionally, ensure that the `GEMINI_API_KEY` environment variable is set with a valid Gemini API key. For instructions on obtaining your API key, refer to the [Gemini documentation](https://ai.google.dev/gemini-api/docs/api-key).
+6 -6
View File
@@ -142,7 +142,8 @@ The JSON-OCSF output format implements the [Detection Finding](https://schema.oc
"desc": "Ensure CloudTrail is enabled in all regions",
"product_uid": "prowler",
"title": "Ensure CloudTrail is enabled in all regions",
"uid": "prowler-aws-cloudtrail_multi_region_enabled-123456789012-ap-northeast-1-123456789012"
"uid": "prowler-aws-cloudtrail_multi_region_enabled-123456789012-ap-northeast-1-123456789012",
"types": ["Software and Configuration Checks","Industry and Regulatory Standards","CIS AWS Foundations Benchmark"],
},
"resources": [
{
@@ -189,11 +190,10 @@ The JSON-OCSF output format implements the [Detection Finding](https://schema.oc
"type_uid": 200401,
"type_name": "Create",
"unmapped": {
"check_type": "Software and Configuration Checks,Industry and Regulatory Standards,CIS AWS Foundations Benchmark",
"related_url": "",
"categories": "forensics-ready",
"depends_on": "",
"related_to": "",
"categories": ["forensics-ready"],
"depends_on": [],
"related_to": [],
"notes": "",
"compliance": {
"CISA": [
@@ -336,7 +336,7 @@ The following is the mapping between the native JSON and the Detection Finding f
| Provider | cloud.provider |
| CheckID | metadata.event_code |
| CheckTitle | finding_info.title |
| CheckType | unmapped.check_type |
| CheckType | finding_info.types |
| ServiceName | resources.group.name |
| SubServiceName | _Not mapped yet_ |
| Status | status_code |
+2
View File
@@ -65,6 +65,7 @@ nav:
- Pentesting: tutorials/pentesting.md
- Parallel Execution: tutorials/parallel-execution.md
- Developer Guide: developer-guide/introduction.md
- Prowler Check Kreator: tutorials/prowler-check-kreator.md
- AWS:
- Authentication: tutorials/aws/authentication.md
- Assume Role: tutorials/aws/role-assumption.md
@@ -87,6 +88,7 @@ nav:
- Google Cloud:
- Authentication: tutorials/gcp/authentication.md
- Projects: tutorials/gcp/projects.md
- Organization: tutorials/gcp/organization.md
- Kubernetes:
- In-Cluster Execution: tutorials/kubernetes/in-cluster.md
- Non In-Cluster Execution: tutorials/kubernetes/outside-cluster.md
@@ -59,9 +59,12 @@ Resources:
- 'appstream:Describe*'
- 'appstream:List*'
- 'backup:List*'
- 'bedrock:List*'
- 'bedrock:Get*'
- 'cloudtrail:GetInsightSelectors'
- 'codeartifact:List*'
- 'codebuild:BatchGet*'
- 'codebuild:ListReportGroups'
- 'cognito-idp:GetUserPoolMfaConfig'
- 'dlm:Get*'
- 'drs:Describe*'
@@ -82,11 +85,14 @@ Resources:
- 'logs:FilterLogEvents'
- 'lightsail:GetRelationalDatabases'
- 'macie2:GetMacieSession'
- 'macie2:GetAutomatedDiscoveryConfiguration'
- 's3:GetAccountPublicAccessBlock'
- 'shield:DescribeProtection'
- 'shield:GetSubscriptionState'
- 'securityhub:BatchImportFindings'
- 'securityhub:GetFindings'
- 'servicecatalog:Describe*'
- 'servicecatalog:List*'
- 'ssm:GetDocument'
- 'ssm-incidents:List*'
- 'support:Describe*'
@@ -7,9 +7,12 @@
"appstream:Describe*",
"appstream:List*",
"backup:List*",
"bedrock:List*",
"bedrock:Get*",
"cloudtrail:GetInsightSelectors",
"codeartifact:List*",
"codebuild:BatchGet*",
"codebuild:ListReportGroups",
"cognito-idp:GetUserPoolMfaConfig",
"dlm:Get*",
"drs:Describe*",
@@ -30,11 +33,14 @@
"logs:FilterLogEvents",
"lightsail:GetRelationalDatabases",
"macie2:GetMacieSession",
"macie2:GetAutomatedDiscoveryConfiguration",
"s3:GetAccountPublicAccessBlock",
"shield:DescribeProtection",
"shield:GetSubscriptionState",
"securityhub:BatchImportFindings",
"securityhub:GetFindings",
"servicecatalog:Describe*",
"servicecatalog:List*",
"ssm:GetDocument",
"ssm-incidents:List*",
"support:Describe*",
Generated
+1851 -1551
View File
File diff suppressed because it is too large. Load diff
+48 -13
View File
@@ -5,6 +5,7 @@ import sys
from os import environ
from colorama import Fore, Style
from colorama import init as colorama_init
from prowler.config.config import (
csv_file_suffix,
@@ -52,6 +53,8 @@ from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS
from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS
from prowler.lib.outputs.compliance.compliance import display_compliance_table
from prowler.lib.outputs.compliance.ens.ens_aws import AWSENS
from prowler.lib.outputs.compliance.ens.ens_azure import AzureENS
from prowler.lib.outputs.compliance.ens.ens_gcp import GCPENS
from prowler.lib.outputs.compliance.generic.generic import GenericCompliance
from prowler.lib.outputs.compliance.iso27001.iso27001_aws import AWSISO27001
from prowler.lib.outputs.compliance.kisa_ismsp.kisa_ismsp_aws import AWSKISAISMSP
@@ -112,6 +115,9 @@ def prowler():
and not checks_folder
)
if args.no_color:
colorama_init(strip=True)
if not args.no_banner:
legend = args.verbose or getattr(args, "fixer", None)
print_banner(legend)
@@ -173,15 +179,15 @@ def prowler():
# Load checks to execute
checks_to_execute = load_checks_to_execute(
bulk_checks_metadata,
bulk_compliance_frameworks,
checks_file,
checks,
services,
severities,
compliance_framework,
categories,
provider,
bulk_checks_metadata=bulk_checks_metadata,
bulk_compliance_frameworks=bulk_compliance_frameworks,
checks_file=checks_file,
check_list=checks,
service_list=services,
severities=severities,
compliance_frameworks=compliance_framework,
categories=categories,
provider=provider,
)
# if --list-checks-json, dump a json file and exit
@@ -236,9 +242,6 @@ def prowler():
# Sort final check list
checks_to_execute = sorted(checks_to_execute)
# Setup Mutelist
global_provider.mutelist = args.mutelist_file
# Setup Output Options
if provider == "aws":
output_options = AWSOutputOptions(
@@ -510,6 +513,20 @@ def prowler():
)
generated_outputs["compliance"].append(mitre_attack)
mitre_attack.batch_write_data_to_file()
elif compliance_name.startswith("ens_"):
# Generate ENS Finding Object
filename = (
f"{output_options.output_directory}/compliance/"
f"{output_options.output_filename}_{compliance_name}.csv"
)
ens = AzureENS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
generated_outputs["compliance"].append(ens)
ens.batch_write_data_to_file()
else:
filename = (
f"{output_options.output_directory}/compliance/"
@@ -554,6 +571,20 @@ def prowler():
)
generated_outputs["compliance"].append(mitre_attack)
mitre_attack.batch_write_data_to_file()
elif compliance_name.startswith("ens_"):
# Generate ENS Finding Object
filename = (
f"{output_options.output_directory}/compliance/"
f"{output_options.output_filename}_{compliance_name}.csv"
)
ens = GCPENS(
findings=finding_outputs,
compliance=bulk_compliance_frameworks[compliance_name],
create_file_descriptor=True,
file_path=filename,
)
generated_outputs["compliance"].append(ens)
ens.batch_write_data_to_file()
else:
filename = (
f"{output_options.output_directory}/compliance/"
@@ -620,7 +651,11 @@ def prowler():
)
security_hub_regions = (
global_provider.get_available_aws_service_regions("securityhub")
global_provider.get_available_aws_service_regions(
"securityhub",
global_provider.identity.partition,
global_provider.identity.audited_regions,
)
if not global_provider.identity.audited_regions
else global_provider.identity.audited_regions
)
@@ -557,7 +557,7 @@
}
],
"Checks": [
"inspector2_findings_exist"
"inspector2_is_enabled"
]
},
{
@@ -587,7 +587,8 @@
}
],
"Checks": [
"inspector2_findings_exist",
"inspector2_active_findings_exist",
"inspector2_is_enabled",
"ecr_registry_scan_images_on_push_enabled",
"ecr_repositories_scan_vulnerabilities_in_latest_image",
"ecr_repositories_scan_images_on_push_enabled"
@@ -28,7 +28,9 @@
"Service": "ebs"
}
],
"Checks": []
"Checks": [
"ec2_ebs_volume_snapshots_exists"
]
},
{
"Id": "1.0.3",
@@ -42,7 +44,8 @@
}
],
"Checks": [
"ec2_ebs_default_encryption"
"ec2_ebs_default_encryption",
"ec2_ebs_volume_encryption"
]
},
{
@@ -87,7 +90,9 @@
}
],
"Checks": [
"iam_user_mfa_enabled_console_access"
"iam_user_mfa_enabled_console_access",
"iam_user_hardware_mfa_enabled",
"iam_root_mfa_enabled"
]
},
{
@@ -102,7 +107,9 @@
}
],
"Checks": [
"iam_user_mfa_enabled_console_access"
"iam_user_mfa_enabled_console_access",
"iam_user_hardware_mfa_enabled",
"iam_root_mfa_enabled"
]
},
{
@@ -117,7 +124,9 @@
}
],
"Checks": [
"iam_root_mfa_enabled"
"iam_root_mfa_enabled",
"iam_root_hardware_mfa_enabled",
"iam_user_mfa_enabled_console_access"
]
},
{
@@ -162,7 +171,10 @@
}
],
"Checks": [
"rds_instance_no_public_access"
"rds_instance_no_public_access",
"s3_bucket_public_access",
"s3_bucket_public_list_acl",
"s3_account_level_public_access_blocks"
]
},
{
@@ -192,7 +204,8 @@
}
],
"Checks": [
"rds_instance_storage_encrypted"
"rds_instance_storage_encrypted",
"rds_instance_transport_encrypted"
]
},
{
@@ -485,7 +485,7 @@
"codeartifact_packages_external_public_publishing_disabled",
"ecr_repositories_not_publicly_accessible",
"efs_not_publicly_accessible",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"elb_internet_facing",
"elbv2_internet_facing",
"s3_account_level_public_access_blocks",
@@ -664,7 +664,7 @@
"awslambda_function_not_publicly_accessible",
"apigateway_restapi_waf_acl_attached",
"cloudfront_distributions_using_waf",
"eks_control_plane_endpoint_access_restricted",
"eks_cluster_not_publicly_accessible",
"sagemaker_models_network_isolation_enabled",
"sagemaker_models_vpc_settings_configured",
"sagemaker_notebook_instance_vpc_settings_configured",
+16 -8
View File
@@ -455,7 +455,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
@@ -476,7 +477,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -497,7 +499,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -518,7 +521,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -540,7 +544,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -561,7 +566,8 @@
],
"Attributes": [
{
"Section": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -578,11 +584,13 @@
"Id": "2.3.1",
"Description": "Ensure that encryption is enabled for RDS Instances",
"Checks": [
"rds_instance_storage_encrypted"
"rds_instance_storage_encrypted",
"rds_instance_transport_encrypted"
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
+22 -11
View File
@@ -455,7 +455,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
@@ -476,7 +477,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -497,7 +499,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -518,7 +521,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -540,7 +544,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -561,7 +566,8 @@
],
"Attributes": [
{
"Section": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -578,11 +584,13 @@
"Id": "2.3.1",
"Description": "Ensure that encryption is enabled for RDS Instances",
"Checks": [
"rds_instance_storage_encrypted"
"rds_instance_storage_encrypted",
"rds_instance_transport_encrypted"
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -603,7 +611,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -624,7 +633,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
@@ -645,7 +655,8 @@
],
"Attributes": [
{
"Section": "2.4 Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "EFS data should be encrypted at rest using AWS KMS (Key Management Service).",
+27 -13
View File
@@ -303,7 +303,9 @@
{
"Id": "1.22",
"Description": "Ensure access to AWSCloudShellFullAccess is restricted",
"Checks": [],
"Checks": [
"iam_policy_cloudshell_admin_not_attached"
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
@@ -474,7 +476,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -491,11 +494,13 @@
"Id": "2.1.2",
"Description": "Ensure MFA Delete is enabled on S3 buckets",
"Checks": [
"s3_bucket_no_mfa_delete"
"s3_bucket_no_mfa_delete",
"cloudtrail_bucket_requires_mfa_delete"
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -516,7 +521,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -538,7 +544,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -559,7 +566,8 @@
],
"Attributes": [
{
"Section": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -576,11 +584,13 @@
"Id": "2.3.1",
"Description": "Ensure that encryption is enabled for RDS Instances",
"Checks": [
"rds_instance_storage_encrypted"
"rds_instance_storage_encrypted",
"rds_instance_transport_encrypted"
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -601,7 +611,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -622,7 +633,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
@@ -643,7 +655,8 @@
],
"Attributes": [
{
"Section": "2.4 Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "EFS data should be encrypted at rest using AWS KMS (Key Management Service).",
@@ -1338,7 +1351,8 @@
"Id": "5.6",
"Description": "Ensure that EC2 Metadata Service only allows IMDSv2",
"Checks": [
"ec2_instance_imdsv2_enabled"
"ec2_instance_imdsv2_enabled",
"ec2_instance_account_imdsv2_enabled"
],
"Attributes": [
{
+18 -9
View File
@@ -474,7 +474,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -495,7 +496,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -516,7 +518,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -538,7 +541,8 @@
],
"Attributes": [
{
"Section": "2.1. Simple Storage Service (S3)",
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -559,7 +563,8 @@
],
"Attributes": [
{
"Section": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -580,7 +585,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -601,7 +607,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -622,7 +629,8 @@
],
"Attributes": [
{
"Section": "2.3. Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to anypublicly accessible RDS database instance, you must disable the database PubliclyAccessible flag and update the VPC security group associated with the instance",
@@ -643,7 +651,8 @@
],
"Attributes": [
{
"Section": "2.4 Relational Database Service (RDS)",
"Section": "2. Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "EFS data should be encrypted at rest using AWS KMS (Key Management Service).",
+3 -29
View File
@@ -2932,7 +2932,7 @@
]
},
{
"Id": "op.pl.2.aws.warch.1",
"Id": "op.pl.2.r1.aws.warch.1",
"Description": "Sistema de gestión",
"Attributes": [
{
@@ -2956,7 +2956,7 @@
"Checks": []
},
{
"Id": "op.pl.2.aws.warch.1",
"Id": "op.pl.2.r2.aws.warch.1",
"Description": "Sistema de gestión de la seguridad con mejora continua",
"Attributes": [
{
@@ -2980,7 +2980,7 @@
"Checks": []
},
{
"Id": "op.pl.2.aws.warch.1",
"Id": "op.pl.2.r3.aws.warch.1",
"Description": "Validación de datos",
"Attributes": [
{
@@ -4304,32 +4304,6 @@
],
"Checks": []
},
{
"Id": "op.mon.3.aws.cwl.1",
"Description": "Vigilancia",
"Attributes": [
{
"IdGrupoControl": "op.mon.3",
"Marco": "operacional",
"Categoria": "monitorización del sistema",
"DescripcionControl": "Deberá asegurarse que todos los servicios que se utilicen en la arquitectura de la aplicación desplegada en AWS estén generando logs",
"Nivel": "alto",
"Tipo": "requisito",
"Dimensiones": [
"confidencialidad",
"integridad",
"trazabilidad",
"autenticidad",
"disponibilidad"
],
"ModoEjecucion": "automatico",
"Dependencias": []
}
],
"Checks": [
"cloudtrail_cloudwatch_logging_enabled"
]
},
{
"Id": "mp.com.2.aws.vpn.1",
"Description": "Protección de la confidencialidad",
@@ -1192,7 +1192,6 @@
"Checks": [
"organizations_scp_check_deny_regions",
"cognito_user_pool_self_registration_disabled",
"cloudtrail_threat_detection_privilege_escalation",
"iam_user_administrator_access_policy",
"iam_customer_unattached_policy_no_administrative_privileges",
"iam_inline_policy_allows_privilege_escalation",
@@ -1510,9 +1509,9 @@
"iam_user_mfa_enabled_console_access",
"networkfirewall_in_all_vpc",
"eks_cluster_network_policy_enabled",
"eks_control_plane_endpoint_access_restricted",
"eks_cluster_not_publicly_accessible",
"eks_cluster_private_nodes_enabled",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"kafka_cluster_is_public",
"kafka_cluster_unrestricted_access_disabled",
"vpc_peering_routing_tables_with_least_privilege",
@@ -2654,7 +2653,6 @@
"accessanalyzer_enabled_without_findings",
"cloudtrail_insights_exist",
"cloudtrail_threat_detection_enumeration",
"cloudtrail_threat_detection_privilege_escalation",
"guardduty_no_high_severity_findings",
"trustedadvisor_errors_and_warnings"
],
@@ -1192,7 +1192,6 @@
"Checks": [
"organizations_scp_check_deny_regions",
"cognito_user_pool_self_registration_disabled",
"cloudtrail_threat_detection_privilege_escalation",
"iam_user_administrator_access_policy",
"iam_customer_unattached_policy_no_administrative_privileges",
"iam_inline_policy_allows_privilege_escalation",
@@ -1510,9 +1509,9 @@
"iam_user_mfa_enabled_console_access",
"networkfirewall_in_all_vpc",
"eks_cluster_network_policy_enabled",
"eks_control_plane_endpoint_access_restricted",
"eks_cluster_not_publicly_accessible",
"eks_cluster_private_nodes_enabled",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"kafka_cluster_is_public",
"kafka_cluster_unrestricted_access_disabled",
"vpc_peering_routing_tables_with_least_privilege",
@@ -2654,7 +2653,6 @@
"accessanalyzer_enabled_without_findings",
"cloudtrail_insights_exist",
"cloudtrail_threat_detection_enumeration",
"cloudtrail_threat_detection_privilege_escalation",
"guardduty_no_high_severity_findings",
"trustedadvisor_errors_and_warnings"
],
@@ -19,7 +19,7 @@
"ec2_ebs_public_snapshot",
"ec2_instance_profile_attached",
"ec2_instance_public_ip",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"emr_cluster_master_nodes_no_public_ip",
"iam_aws_attached_policy_no_administrative_privileges",
"iam_customer_attached_policy_no_administrative_privileges",
@@ -61,7 +61,7 @@
"ec2_ebs_public_snapshot",
"ec2_instance_profile_attached",
"ec2_instance_public_ip",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"emr_cluster_master_nodes_no_public_ip",
"iam_aws_attached_policy_no_administrative_privileges",
"iam_customer_attached_policy_no_administrative_privileges",
@@ -102,7 +102,7 @@
"Checks": [
"ec2_ebs_public_snapshot",
"ec2_instance_public_ip",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"emr_cluster_master_nodes_no_public_ip",
"awslambda_function_not_publicly_accessible",
"awslambda_function_url_public",
+1 -1
View File
@@ -971,7 +971,7 @@
"Checks": [
"ec2_ebs_public_snapshot",
"ec2_instance_public_ip",
"eks_endpoints_not_publicly_accessible",
"eks_cluster_not_publicly_accessible",
"emr_cluster_master_nodes_no_public_ip",
"awslambda_function_url_public",
"rds_instance_no_public_access",
+179 -102
View File
@@ -12,7 +12,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1. Identity and Access Management",
"SubSection": "1.1 Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Security defaults in Azure Active Directory (Azure AD) make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security",
@@ -34,7 +35,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1. Identity and Access Management",
"SubSection": "1.1 Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. These include custom created objects or built-in roles such as; • Service Co-Administrators • Subscription Owners • Contributors",
@@ -56,7 +58,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1. Identity and Access Management",
"SubSection": "1.1 Security Defaults",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable multi-factor authentication for all non-privileged users.",
@@ -76,7 +79,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1. Identity and Access Management",
"SubSection": "1.1 Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Do not allow users to remember multi-factor authentication on devices.",
@@ -98,7 +102,8 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Azure Active Directory Conditional Access allows an organization to configure Named locations and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization.",
@@ -118,7 +123,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "CAUTION: If these policies are created without first auditing and testing the result, misconfiguration can potentially lock out administrators or create undesired access issues. Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined.",
@@ -138,7 +144,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login.",
@@ -158,7 +165,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins.",
@@ -178,7 +186,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login.",
@@ -198,7 +207,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins.",
@@ -220,7 +230,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Require administrators or appropriately delegated users to create new tenants.",
@@ -240,7 +250,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "This recommendation extends guest access review by utilizing the Azure AD Privileged Identity Management feature provided in Azure AD Premium P2. Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources a a guest user.",
@@ -260,7 +270,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Azure AD is extended to include Azure AD B2B collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account and sign in with their own work, school, or social identities. Guest users allow you to share your company's applications and services with users from any other organization, while maintaining control over your own corporate data. Work with external partners, large or small, even if they don't have Azure AD or an IT department. A simple invitation and redemption process lets partners use their own credentials to access your company's resources as a guest user. Guest users in every subscription should be review on a regular basis to ensure that inactive and unneeded accounts are removed.",
@@ -280,7 +290,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensures that two alternate forms of identification are provided before allowing a password reset.",
@@ -300,7 +310,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Microsoft Azure provides a Global Banned Password policy that applies to Azure administrative and normal user accounts. This is not applied to user accounts that are synced from an on-premise Active Directory unless Azure AD Connect is used and you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers. Please see the list in default values on the specifics of this policy. To further password security, it is recommended to further define a custom banned password policy.",
@@ -320,7 +330,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure that the number of days before users are asked to re-confirm their authentication information is not set to 0.",
@@ -340,7 +350,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure that users are notified on their primary and secondary emails on password resets.",
@@ -360,7 +370,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure that all Global Administrators are notified if any other administrator resets their password.",
@@ -382,7 +392,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Require administrators to provide consent for applications before use.",
@@ -404,7 +414,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Allow users to provide consent for selected permissions when a request is coming from a verified publisher.",
@@ -424,7 +434,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Require administrators to provide consent for the apps before use.",
@@ -446,7 +456,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Require administrators or appropriately delegated users to register third-party applications.",
@@ -468,7 +478,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Limit guest user permissions.",
@@ -490,7 +500,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Restrict invitations to users with specific administrative roles only.",
@@ -510,7 +520,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Restrict access to the Azure AD administration portal to administrators only. NOTE: This only affects access to the Azure AD administrator's web portal. This setting does not prohibit privileged users from using other methods such as Rest API or Powershell to obtain sensitive information from Azure AD.",
@@ -530,7 +540,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Restricts group creation to administrators with permissions only.",
@@ -552,7 +562,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Restrict security group creation to administrators only.",
@@ -572,7 +582,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Restrict security group management to administrators only.",
@@ -594,7 +604,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Restrict Microsoft 365 group creation to administrators only.",
@@ -614,7 +624,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Joining or registering devices to the active directory should require Multi-factor authentication.",
@@ -636,7 +646,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The principle of least privilege should be followed and only necessary privileges should be assigned instead of allowing full administrative access.",
@@ -658,7 +668,7 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Resource locking is a powerful protection mechanism that can prevent inadvertent modification/deletion of resources within Azure subscriptions/Resource Groups and is a recommended NIST configuration.",
@@ -678,7 +688,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1. Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Users who are set as subscription owners are able to make administrative changes to the subscriptions and move them into and out of Azure Active Directories.",
@@ -700,7 +710,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -722,7 +733,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -744,7 +756,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Databases enables threat detection for the instances running your database software. This provides threat intelligence, anomaly detection, and behavior analytics in the Azure Microsoft Defender for Cloud. Instead of being enabled on services like Platform as a Service (PaaS), this implementation will run within your instances as Infrastructure as a Service (IaaS) on the Operating Systems hosting your databases.",
@@ -766,7 +779,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, andbehavior analytics in the Microsoft Defender for Cloud.",
@@ -788,7 +802,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -810,7 +825,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -832,7 +848,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -854,7 +871,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -876,7 +894,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources.",
@@ -898,7 +917,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -920,7 +940,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Microsoft Defender for DNS scans all network traffic exiting from within a subscription.",
@@ -942,7 +963,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal.",
@@ -964,7 +986,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure that the latest OS patches for all virtual machines are applied.",
@@ -986,7 +1009,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "None of the settings offered by ASC Default policy should be set to effect Disabled.",
@@ -1008,7 +1032,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Enable automatic provisioning of the monitoring agent to collect security data.",
@@ -1030,7 +1055,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines.",
@@ -1050,7 +1076,8 @@
"Checks": [],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable automatic provisioning of the Microsoft Defender for Containers components.",
@@ -1072,7 +1099,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enable security alert emails to subscription owners.",
@@ -1094,7 +1122,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address.",
@@ -1116,7 +1145,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enables emailing security alerts to the subscription owner or other designated security contact.",
@@ -1138,7 +1168,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud.",
@@ -1160,7 +1191,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud. IMPORTANT: When enabling integration between DfE & DfC it needs to be taken into account that this will have some side effects that may be undesirable. 1. For server 2019 & above if defender is installed (default for these server SKU's) this will trigger a deployment of the new unified agent and link to any of the extended configuration in the Defender portal. 2. If the new unified agent is required for server SKU's of Win 2016 or Linux and lower there is additional integration that needs to be switched on and agents need to be aligned.",
@@ -1182,7 +1214,8 @@
],
"Attributes": [
{
"Section": "2.2 Microsoft Defender for IoT",
"Section": "2. Microsoft Defender",
"SubSection": "2.2 Microsoft Defender for IoT",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization.",
@@ -1524,7 +1557,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable auditing on SQL Servers.",
@@ -1546,7 +1580,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP).",
@@ -1568,7 +1603,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. With TDE, data is encrypted at rest with a symmetric key (called the database encryption key) stored in the database or data warehouse distribution. To protect this data encryption key (DEK) in the past, only a certificate that the Azure SQL Service managed could be used. Now, with Customer-managed key support for TDE, the DEK can be protected with an asymmetric key that is stored in the Azure Key Vault. The Azure Key Vault is a highly available and scalable cloud-based key store which offers central key management, leverages FIPS 140-2 Level 2 validated hardware security modules (HSMs), and allows separation of management of keys and data for additional security. Based on business needs or criticality of data/databases hosted on a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key).",
@@ -1590,7 +1626,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Use Azure Active Directory Authentication for authentication with SQL Database to manage credentials in a single place.",
@@ -1612,7 +1649,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable Transparent Data Encryption on every SQL server.",
@@ -1634,7 +1672,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "SQL Server Audit Retention should be configured to be greater than 90 days.",
@@ -1656,7 +1695,8 @@
],
"Attributes": [
{
"Section": "4.2 SQL Server - Microsoft Defender for SQL",
"Section": "4. Database Services",
"SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enable 'Microsoft Defender for SQL' on critical SQL Servers.",
@@ -1678,7 +1718,8 @@
],
"Attributes": [
{
"Section": "4.2 SQL Server - Microsoft Defender for SQL",
"Section": "4. Database Services",
"SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases.",
@@ -1700,7 +1741,8 @@
],
"Attributes": [
{
"Section": "4.2 SQL Server - Microsoft Defender for SQL",
"Section": "4. Database Services",
"SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enable Vulnerability Assessment (VA) service scans for critical SQL servers and corresponding SQL databases.",
@@ -1722,7 +1764,8 @@
],
"Attributes": [
{
"Section": "4.2 SQL Server - Microsoft Defender for SQL",
"Section": "4. Database Services",
"SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Configure 'Send scan reports to' with email addresses of concerned data owners/stakeholders for a critical SQL servers",
@@ -1744,7 +1787,8 @@
],
"Attributes": [
{
"Section": "4.2 SQL Server - Microsoft Defender for SQL",
"Section": "4. Database Services",
"SubSection": "4.2 SQL Server - Microsoft Defender for SQL",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable Vulnerability Assessment (VA) setting 'Also send email notifications to admins and subscription owners'.",
@@ -1766,7 +1810,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable SSL connection on PostgreSQL Servers.",
@@ -1788,7 +1833,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable log_checkpoints on PostgreSQL Servers.",
@@ -1810,7 +1856,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable log_connections on PostgreSQL Servers.",
@@ -1832,7 +1879,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable log_disconnections on PostgreSQL Servers.",
@@ -1854,7 +1902,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable connection_throttling on PostgreSQL Servers.",
@@ -1876,7 +1925,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure log_retention_days on PostgreSQL Servers is set to an appropriate value.",
@@ -1898,7 +1948,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Disable access from Azure services to PostgreSQL Database Server.",
@@ -1918,7 +1969,8 @@
"Checks": [],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled.",
@@ -1940,7 +1992,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable SSL connection on MYSQL Servers.",
@@ -1962,7 +2015,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure TLS version on MySQL flexible servers is set to the default value.",
@@ -1984,7 +2038,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable audit_log_enabled on MySQL Servers.",
@@ -2006,7 +2061,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Set audit_log_enabled to include CONNECTION on MySQL Servers.",
@@ -2028,7 +2084,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint.",
@@ -2050,7 +2107,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Private endpoints limit network traffic to approved sources.",
@@ -2072,7 +2130,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Cosmos DB can use tokens or AAD for client authentication which in turn will use Azure RBAC for authorization. Using AAD is significantly more secure because AAD handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure.",
@@ -2094,7 +2153,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Enable Diagnostic settings for exporting activity logs. Diagnos tic settings are available for each individual resource within a subscription. Settings should be configured for allappropriate resources for your environment.",
@@ -2116,7 +2176,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Prerequisite: A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: 'Ensure that a 'Diagnostic Setting' exists.' The diagnostic setting should be configured to log the appropriate activities from the control/management plane.",
@@ -2138,7 +2199,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The storage account container containing the activity log export should not be publicly accessible.",
@@ -2160,7 +2222,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK).",
@@ -2182,7 +2245,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available.",
@@ -2204,7 +2268,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Ensure that network flow logs are captured and fed into a central log analytics workspace.",
@@ -2226,7 +2291,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged.",
@@ -2248,7 +2314,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create Policy Assignment event.",
@@ -2270,7 +2337,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Policy Assignment event.",
@@ -2292,7 +2360,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an Activity Log Alert for the Create or Update Network Security Group event.",
@@ -2314,7 +2383,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Network Security Group event.",
@@ -2336,7 +2406,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update Security Solution event.",
@@ -2358,7 +2429,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Security Solution event.",
@@ -2380,7 +2452,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update SQL Server Firewall Rule event.",
@@ -2402,7 +2475,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the 'Delete SQL Server Firewall Rule.'",
@@ -2424,7 +2498,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update Public IP Addresses rule.",
@@ -2446,7 +2521,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Public IP Address rule.",
@@ -2466,7 +2542,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5.3 Configuring Application Insights",
"Section": "5. Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Resource Logs capture activity to the data access plane while the Activity log is a subscription-level log for the control plane. Resource-level diagnostic logs provide insight into operations that were performed within that resource itself; for example, reading or updating a secret from a Key Vault. Currently, 95 Azure resources support Azure Monitoring (See the more information section for a complete list), including Network Security Groups, Load Balancers, Key Vault, AD, Logic Apps, and CosmosDB. The content of these logs varies by resource type. A number of back-end services were not configured to log and store Resource Logs for certain activities or for a sufficient length. It is crucial that monitoring is correctly configured to log all relevant activities and retain those logs for a sufficient length of time. Given that the mean time to detection in an enterprise is 240 days, a minimum retention period of two years is recommended.",
@@ -2486,7 +2562,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5.3 Configuring Application Insights",
"Section": "5. Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The use of Basic or Free SKUs in Azure whilst cost effective have significant limitations in terms of what can be monitored and what support can be realized from Microsoft. Typically, these SKU’s do not have a service SLA and Microsoft will usually refuse to provide support for them. Consequently Basic/Free SKUs should never be used for production workloads.",
@@ -2508,7 +2584,8 @@
],
"Attributes": [
{
"Section": "5.3 Configuring Application Insights",
"Section": "5. Logging and Monitoring",
"SubSection": "5.3 Configuring Application Insights",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions. Both data sets help organizations adopt a proactive and retroactive means to handle security and performance related metrics within their modern applications.",
+146 -76
View File
@@ -494,7 +494,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults Security Defaults",
"Section": "1.Identity and Access Management",
"SubSection": "1.1 Security Defaults Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Security defaults in Microsoft Entra ID make it easier to be secure and help protect your organization. Security defaults contain preconfigured security settings for common attacks. Security defaults is available to everyone. The goal is to ensure that all organizations have a basic level of security enabled at no extra cost. You may turn on security defaults in the Azure portal.",
@@ -516,7 +517,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults Security Defaults",
"Section": "1.Identity and Access Management",
"SubSection": "1.1 Security Defaults Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Enable multi-factor authentication for all roles, groups, and users that have write access or permissions to Azure resources. These include custom created objects or built-in roles such as; - Service Co-Administrators - Subscription Owners - Contributors",
@@ -538,7 +540,8 @@
],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1.Identity and Access Management",
"SubSection": "1.1 Security Defaults Security Defaults",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable multi-factor authentication for all non-privileged users.",
@@ -558,7 +561,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.1 Security Defaults",
"Section": "1.Identity and Access Management",
"SubSection": "1.1 Security Defaults Security Defaults",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Do not allow users to remember multi-factor authentication on devices.",
@@ -580,7 +584,8 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Microsoft Entra ID Conditional Access allows an organization to configure `Named locations` and configure whether those locations are trusted or untrusted. These settings provide organizations the means to specify Geographical locations for use in conditional access policies, or define actual IP addresses and IP ranges and whether or not those IP addresses and/or ranges are trusted by the organization.",
@@ -600,7 +605,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "**CAUTION**: If these policies are created without first auditing and testing the result, misconfiguration can potentially lock out administrators or create undesired access issues. Conditional Access Policies can be used to block access from geographic locations that are deemed out-of-scope for your organization or application. The scope and variables for this policy should be carefully examined and defined.",
@@ -620,7 +626,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login.",
@@ -640,7 +647,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on logins.",
@@ -660,7 +668,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "For designated users, they will be prompted to use their multi-factor authentication (MFA) process on login.",
@@ -682,7 +691,8 @@
],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "This recommendation ensures that users accessing the Windows Azure Service Management API (i.e. Azure Powershell, Azure CLI, Azure Resource Manager API, etc.) are required to use multifactor authentication (MFA) credentials when accessing resources through the Windows Azure Service Management API.",
@@ -702,7 +712,8 @@
"Checks": [],
"Attributes": [
{
"Section": "1.2 Conditional Access",
"Section": "1.Identity and Access Management",
"SubSection": "1.2 Conditional Access",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "This recommendation ensures that users accessing Microsoft Admin Portals (i.e. Microsoft 365 Admin, Microsoft 365 Defender, Exchange Admin Center, Azure Portal, etc.) are required to use multifactor authentication (MFA) credentials when logging into an Admin Portal.",
@@ -724,7 +735,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Servers enables threat detection for Servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -746,7 +758,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for App Service enables threat detection for App Service, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -768,7 +781,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Azure SQL Databases enables threat detection for Managed Instance Azure SQL databases, providing threat intelligence, anomaly detection, and behavior analytics in Microsoft Defender for Cloud.",
@@ -790,7 +804,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for SQL servers on machines enables threat detection for SQL servers on machines, providing threat intelligence, anomaly detection, and behavior analytics in Microsoft Defender for Cloud.",
@@ -812,7 +827,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Open-source relational databases enables threat detection for Open-source relational databases, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -834,7 +850,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Microsoft Defender for Azure Cosmos DB scans all incoming network requests for threats to your Azure Cosmos DB resources.",
@@ -856,7 +873,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Storage enables threat detection for Storage, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -878,7 +896,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Containers enables threat detection for Container Registries including Kubernetes, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud. The following services will be enabled for container instances: - Defender agent in Azure - Azure Policy for Kubernetes - Agentless discovery for Kubernetes - Agentless container vulnerability assessment",
@@ -900,7 +919,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Turning on Microsoft Defender for Key Vault enables threat detection for Key Vault, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.",
@@ -922,7 +942,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "[**NOTE:** As of August 1, customers with an existing subscription to Defender for DNS can continue to use the service, but new subscribers will receive alerts about suspicious DNS activity as part of Defender for Servers P2.] Microsoft Defender for DNS scans all network traffic exiting from within a subscription.",
@@ -944,7 +965,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Microsoft Defender for Resource Manager scans incoming administrative requests to change your infrastructure from both CLI and the Azure portal.",
@@ -966,7 +988,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that the latest OS patches for all virtual machines are applied.",
@@ -988,7 +1011,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The Microsoft Cloud Security Benchmark (or MCSB) is an Azure Policy Initiative containing many security policies to evaluate resource configuration against best practice recommendations. If a policy in the MCSB is set with effect type `Disabled`, it is not evaluated and may prevent administrators from being informed of valuable security recommendations.",
@@ -1010,7 +1034,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable automatic provisioning of the monitoring agent to collect security data.",
@@ -1032,7 +1057,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable automatic provisioning of vulnerability assessment for machines on both Azure and hybrid (Arc enabled) machines.",
@@ -1052,7 +1078,8 @@
"Checks": [],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enable automatic provisioning of the Microsoft Defender for Containers components.",
@@ -1074,7 +1101,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable security alert emails to subscription owners.",
@@ -1096,7 +1124,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Microsoft Defender for Cloud emails the subscription owners whenever a high-severity alert is triggered for their subscription. You should provide a security contact email address as an additional email address.",
@@ -1118,7 +1147,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enables emailing security alerts to the subscription owner or other designated security contact.",
@@ -1140,7 +1170,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "This integration setting enables Microsoft Defender for Cloud Apps (formerly 'Microsoft Cloud App Security' or 'MCAS' - see additional info) to communicate with Microsoft Defender for Cloud.",
@@ -1162,7 +1193,8 @@
],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "This integration setting enables Microsoft Defender for Endpoint (formerly 'Advanced Threat Protection' or 'ATP' or 'WDATP' - see additional info) to communicate with Microsoft Defender for Cloud. **IMPORTANT:** When enabling integration between DfE & DfC it needs to be taken into account that this will have some side effects that may be undesirable. 1. For server 2019 & above if defender is installed (default for these server SKU's) this will trigger a deployment of the new unified agent and link to any of the extended configuration in the Defender portal. 1. If the new unified agent is required for server SKU's of Win 2016 or Linux and lower there is additional integration that needs to be switched on and agents need to be aligned.",
@@ -1182,7 +1214,8 @@
"Checks": [],
"Attributes": [
{
"Section": "2.1 Microsoft Defender for Cloud",
"Section": "2. Microsoft Defender",
"SubSection": "2.1 Microsoft Defender for Cloud",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "An organization's attack surface is the collection of assets with a public network identifier or URI that an external threat actor can see or access from outside your cloud. It is the set of points on the boundary of a system, a system element, system component, or an environment where an attacker can try to enter, cause an effect on, or extract data from, that system, system element, system component, or environment. The larger the attack surface, the harder it is to protect. This tool can be configured to scan your organization's online infrastructure such as specified domains, hosts, CIDR blocks, and SSL certificates, and store them in an Inventory. Inventory items can be added, reviewed, approved, and removed, and may contain enrichments (insights) and additional information collected from the tool's different scan engines and open-source intelligence sources. A Defender EASM workspace will generate an Inventory of publicly exposed assets by crawling and scanning the internet using _Seeds_ you provide when setting up the tool. Seeds can be FQDNs, IP CIDR blocks, and WHOIS records. Defender EASM will generate Insights within 24-48 hours after Seeds are provided, and these insights include vulnerability data (CVEs), ports and protocols, and weak or expired SSL certificates that could be used by an attacker for reconnaisance or exploitation. Results are classified High/Medium/Low and some of them include proposed mitigations.",
@@ -1204,7 +1237,8 @@
],
"Attributes": [
{
"Section": "2.2 Microsoft Defender for IoT",
"Section": "2. Microsoft Defender",
"SubSection": "2.2 Microsoft Defender for IoT",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Microsoft Defender for IoT acts as a central security hub for IoT devices within your organization.",
@@ -1586,7 +1620,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable auditing on SQL Servers.",
@@ -1608,7 +1643,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that no SQL Databases allow ingress from 0.0.0.0/0 (ANY IP).",
@@ -1630,7 +1666,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Transparent Data Encryption (TDE) with Customer-managed key support provides increased transparency and control over the TDE Protector, increased security with an HSM-backed external service, and promotion of separation of duties. With TDE, data is encrypted at rest with a symmetric key (called the database encryption key) stored in the database or data warehouse distribution. To protect this data encryption key (DEK) in the past, only a certificate that the Azure SQL Service managed could be used. Now, with Customer-managed key support for TDE, the DEK can be protected with an asymmetric key that is stored in the Azure Key Vault. The Azure Key Vault is a highly available and scalable cloud-based key store which offers central key management, leverages FIPS 140-2 Level 2 validated hardware security modules (HSMs), and allows separation of management of keys and data for additional security. Based on business needs or criticality of data/databases hosted on a SQL server, it is recommended that the TDE protector is encrypted by a key that is managed by the data owner (Customer-managed key).",
@@ -1652,7 +1689,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Use Microsoft Entra authentication for authentication with SQL Database to manage credentials in a single place.",
@@ -1674,7 +1712,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable Transparent Data Encryption on every SQL server.",
@@ -1696,7 +1735,8 @@
],
"Attributes": [
{
"Section": "4.1 SQL Server - Auditing",
"Section": "4. Database Services",
"SubSection": "4.1 SQL Server - Auditing",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "SQL Server Audit Retention should be configured to be greater than 90 days.",
@@ -1718,7 +1758,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `SSL connection` on `PostgreSQL` Servers.",
@@ -1740,7 +1781,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `log_checkpoints` on `PostgreSQL Servers`.",
@@ -1762,7 +1804,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `log_connections` on `PostgreSQL Servers`.",
@@ -1784,7 +1827,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `log_disconnections` on `PostgreSQL Servers`.",
@@ -1806,7 +1850,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `connection_throttling` on `PostgreSQL Servers`.",
@@ -1828,7 +1873,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure `log_retention_days` on `PostgreSQL Servers` is set to an appropriate value.",
@@ -1850,7 +1896,8 @@
],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Disable access from Azure services to PostgreSQL Database Server.",
@@ -1870,7 +1917,8 @@
"Checks": [],
"Attributes": [
{
"Section": "4.3 PostgreSQL Database Server. Storage Accounts",
"Section": "4. Database Services",
"SubSection": "4.3 PostgreSQL Database Server. Storage Accounts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Azure Database for PostgreSQL servers should be created with 'infrastructure double encryption' enabled.",
@@ -1892,7 +1940,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable `SSL connection` on `MYSQL` Servers.",
@@ -1914,7 +1963,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure `TLS version` on `MySQL flexible` servers is set to use TLS version 1.2 or higher.",
@@ -1936,7 +1986,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable audit_log_enabled on MySQL Servers.",
@@ -1958,7 +2009,8 @@
],
"Attributes": [
{
"Section": "4.4 MySQL Database",
"Section": "4. Database Services",
"SubSection": "4.4 MySQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Set `audit_log_enabled` to include CONNECTION on MySQL Servers.",
@@ -1980,7 +2032,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Limiting your Cosmos DB to only communicate on whitelisted networks lowers its attack footprint.",
@@ -2002,7 +2055,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Private endpoints limit network traffic to approved sources.",
@@ -2024,7 +2078,8 @@
],
"Attributes": [
{
"Section": "4.5 Cosmos DB",
"Section": "4. Database Services",
"SubSection": "4.5 Cosmos DB",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Cosmos DB can use tokens or Entra ID for client authentication which in turn will use Azure RBAC for authorization. Using Entra ID is significantly more secure because Entra ID handles the credentials and allows for MFA and centralized management, and the Azure RBAC better integrated with the rest of Azure.",
@@ -2086,7 +2141,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Enable Diagnostic settings for exporting activity logs. Diagnostic settings are available for each individual resource within a subscription. Settings should be configured for all appropriate resources for your environment.",
@@ -2108,7 +2164,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "**Prerequisite**: A Diagnostic Setting must exist. If a Diagnostic Setting does not exist, the navigation and options within this recommendation will not be available. Please review the recommendation at the beginning of this subsection titled: Ensure that a 'Diagnostic Setting' exists. The diagnostic setting should be configured to log the appropriate activities from the control/management plane.",
@@ -2130,7 +2187,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Storage accounts with the activity log exports can be configured to use Customer Managed Keys (CMK).",
@@ -2152,7 +2210,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable AuditEvent logging for key vault instances to ensure interactions with key vaults are logged and available.",
@@ -2174,7 +2233,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Ensure that network flow logs are captured and fed into a central log analytics workspace.",
@@ -2196,7 +2256,8 @@
],
"Attributes": [
{
"Section": "5.1 Configuring Diagnostic Settings",
"Section": "5. Logging and Monitoring",
"SubSection": "5.1 Configuring Diagnostic Settings",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Enable AppServiceHTTPLogs diagnostic log category for Azure App Service instances to ensure all http requests are captured and centrally logged.",
@@ -2218,7 +2279,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create Policy Assignment event.",
@@ -2240,7 +2302,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Policy Assignment event.",
@@ -2262,7 +2325,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an Activity Log Alert for the Create or Update Network Security Group event.",
@@ -2284,7 +2348,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Network Security Group event.",
@@ -2306,7 +2371,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update Security Solution event.",
@@ -2328,7 +2394,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Security Solution event.",
@@ -2350,7 +2417,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update SQL Server Firewall Rule event.",
@@ -2372,7 +2440,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete SQL Server Firewall Rule.",
@@ -2394,7 +2463,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Create or Update Public IP Addresses rule.",
@@ -2416,7 +2486,8 @@
],
"Attributes": [
{
"Section": "5.2 Monitoring using Activity Log Alerts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.2 Monitoring using Activity Log Alerts",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Create an activity log alert for the Delete Public IP Address rule.",
@@ -2438,7 +2509,8 @@
],
"Attributes": [
{
"Section": "5.3 Configuring Application Insights. Storage Accounts",
"Section": "5. Logging and Monitoring",
"SubSection": "5.3 Configuring Application Insights. Storage Accounts",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Application Insights within Azure act as an Application Performance Monitoring solution providing valuable data into how well an application performs and additional information when performing incident response. The types of log data collected include application metrics, telemetry data, and application trace logging data providing organizations with detailed information about application activity and application transactions. Both data sets help organizations adopt a proactive and retroactive means to handle security and performance related metrics within their modern applications.",
@@ -3044,7 +3116,7 @@
"Id": "9.4",
"Description": "Ensure that Register with Entra ID is enabled on App Service",
"Checks": [
""
"app_register_with_identity"
],
"Attributes": [
{
@@ -3175,9 +3247,7 @@
{
"Id": "9.10",
"Description": "Ensure Azure Key Vaults are Used to Store Secrets",
"Checks": [
""
],
"Checks": [],
"Attributes": [
{
"Section": "9. AppService",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+38 -19
View File
@@ -1292,7 +1292,8 @@
"Checks": [],
"Attributes": [
{
"Section": "6.1. MySQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "It is recommended to set a password for the administrative user (`root` by default) to prevent unauthorized access to the SQL database instances. This recommendation is applicable only for MySQL Instances. PostgreSQL does not offer any setting for No Password from the cloud console.",
@@ -1313,7 +1314,8 @@
],
"Attributes": [
{
"Section": "6.1. MySQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `skip_show_database` database flag for Cloud SQL Mysql instance to `on`",
@@ -1334,7 +1336,8 @@
],
"Attributes": [
{
"Section": "6.1. MySQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set the `local_infile` database flag for a Cloud SQL MySQL instance to `off`.",
@@ -1355,7 +1358,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The `log_error_verbosity` flag controls the verbosity/details of messages logged. Valid values are: - `TERSE` - `DEFAULT` - `VERBOSE` `TERSE` excludes the logging of `DETAIL`, `HINT`, `QUERY`, and `CONTEXT` error information. `VERBOSE` output includes the `SQLSTATE` error code, source code file name, function name, and line number that generated the error. Ensure an appropriate value is set to 'DEFAULT' or stricter.",
@@ -1376,7 +1380,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_error_statement` flag defines the minimum message severity level that are considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. Ensure a value of `ERROR` or stricter is set.",
@@ -1397,7 +1402,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The value of `log_statement` flag determined the SQL statements that are logged. Valid values are: - `none` - `ddl` - `mod` - `all` The value `ddl` logs all data definition statements. The value `mod` logs all ddl statements, plus data-modifying statements. The statements are logged after a basic parsing is done and statement type is determined, thus this does not logs statements with errors. When using extended query protocol, logging occurs after an Execute message is received and values of the Bind parameters are included. A value of 'ddl' is recommended unless otherwise directed by your organization's logging policy.",
@@ -1418,7 +1424,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Instance addresses can be public IP or private IP. Public IP means that the instance is accessible through the public internet. In contrast, instances using only private IP are not accessible through the public internet, but are accessible through a Virtual Private Cloud (VPC). Limiting network access to your database will limit potential attacks.",
@@ -1439,7 +1446,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure `cloudsql.enable_pgaudit` database flag for Cloud SQL PostgreSQL instance is set to `on` to allow for centralized logging.",
@@ -1460,7 +1468,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_connections` setting causes each attempted connection to the server to be logged, along with successful completion of client authentication. This parameter cannot be changed after the session starts.",
@@ -1481,7 +1490,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_disconnections` setting logs the end of each session, including the session duration.",
@@ -1502,7 +1512,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_duration_statement` flag defines the minimum amount of execution time of a statement in milliseconds where the total duration of the statement is logged. Ensure that `log_min_duration_statement` is disabled, i.e., a value of `-1` is set.",
@@ -1523,7 +1534,8 @@
],
"Attributes": [
{
"Section": "6.2. PostgreSQL Database",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_messages` flag defines the minimum message severity level that is considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. ERROR is considered the best practice setting. Changes should only be made in accordance with the organization's logging policy.",
@@ -1544,7 +1556,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `3625 (trace flag)` database flag for Cloud SQL SQL Server instance to `on`.",
@@ -1565,7 +1578,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `external scripts enabled` database flag for Cloud SQL SQL Server instance to `off`",
@@ -1586,7 +1600,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `remote access` database flag for Cloud SQL SQL Server instance to `off`.",
@@ -1607,7 +1622,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to check the `user connections` for a Cloud SQL SQL Server instance to ensure that it is not artificially limiting connections.",
@@ -1628,7 +1644,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that, `user options` database flag for Cloud SQL SQL Server instance should not be configured.",
@@ -1649,7 +1666,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `contained database authentication` database flag for Cloud SQL on the SQL Server instance to `off`.",
@@ -1670,7 +1688,8 @@
],
"Attributes": [
{
"Section": "6.3. SQL Server",
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `cross db ownership chaining` database flag for Cloud SQL SQL Server instance to `off`.",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+10 -4
View File
@@ -1,6 +1,7 @@
import os
import pathlib
from datetime import datetime, timezone
from enum import Enum
from os import getcwd
import requests
@@ -11,7 +12,7 @@ from prowler.lib.logger import logger
timestamp = datetime.today()
timestamp_utc = datetime.now(timezone.utc).replace(tzinfo=timezone.utc)
prowler_version = "4.5.0"
prowler_version = "4.6.3"
html_logo_url = "https://github.com/prowler-cloud/prowler/"
square_logo_img = "https://prowler.com/wp-content/uploads/logo-html.png"
aws_logo = "https://user-images.githubusercontent.com/38561120/235953920-3e3fba08-0795-41dc-b480-9bea57db9f2e.png"
@@ -21,8 +22,13 @@ gcp_logo = "https://user-images.githubusercontent.com/38561120/235928332-eb4accd
orange_color = "\033[38;5;208m"
banner_color = "\033[1;92m"
finding_statuses = ["PASS", "FAIL", "MANUAL"]
valid_severities = ["critical", "high", "medium", "low", "informational"]
class Provider(str, Enum):
AWS = "aws"
GCP = "gcp"
AZURE = "azure"
KUBERNETES = "kubernetes"
# Compliance
actual_directory = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
@@ -30,7 +36,7 @@ actual_directory = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
def get_available_compliance_frameworks(provider=None):
available_compliance_frameworks = []
providers = ["aws", "gcp", "azure", "kubernetes"]
providers = [p.value for p in Provider]
if provider:
providers = [provider]
for provider in providers:
+43 -2
View File
@@ -91,6 +91,7 @@ aws:
"python3.6",
"python2.7",
"python3.7",
"python3.8",
"nodejs4.3",
"nodejs4.3-edge",
"nodejs6.10",
@@ -99,7 +100,10 @@ aws:
"nodejs10.x",
"nodejs12.x",
"nodejs14.x",
"nodejs16.x",
"dotnet5.0",
"dotnet6",
"dotnet7",
"dotnetcore1.0",
"dotnetcore2.0",
"dotnetcore2.1",
@@ -133,7 +137,7 @@ aws:
# AWS CloudTrail Configuration
# aws.cloudtrail_threat_detection_privilege_escalation
threat_detection_privilege_escalation_threshold: 0.1 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.1 (10%)
threat_detection_privilege_escalation_threshold: 0.2 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.2 (20%)
threat_detection_privilege_escalation_minutes: 1440 # Past minutes to search from now for privilege_escalation attacks, by default is 1440 minutes (24 hours)
threat_detection_privilege_escalation_actions:
[
@@ -190,7 +194,7 @@ aws:
"UpdateLoginProfile",
]
# aws.cloudtrail_threat_detection_enumeration
threat_detection_enumeration_threshold: 0.1 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.1 (10%)
threat_detection_enumeration_threshold: 0.3 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.3 (30%)
threat_detection_enumeration_minutes: 1440 # Past minutes to search from now for enumeration attacks, by default is 1440 minutes (24 hours)
threat_detection_enumeration_actions:
[
@@ -285,6 +289,24 @@ aws:
"LookupEvents",
"Search",
]
# aws.cloudtrail_threat_detection_llm_jacking
threat_detection_llm_jacking_threshold: 0.4 # Percentage of actions found to decide if it is an LLM Jacking attack event, by default is 0.4 (40%)
threat_detection_llm_jacking_minutes: 1440 # Past minutes to search from now for LLM Jacking attacks, by default is 1440 minutes (24 hours)
threat_detection_llm_jacking_actions:
[
"PutUseCaseForModelAccess", # Submits a use case for model access, providing justification (Write).
"PutFoundationModelEntitlement", # Grants entitlement for accessing a foundation model (Write).
"PutModelInvocationLoggingConfiguration", # Configures logging for model invocations (Write).
"CreateFoundationModelAgreement", # Creates a new agreement to use a foundation model (Write).
"InvokeModel", # Invokes a specified Bedrock model for inference using provided prompt and parameters (Read).
"InvokeModelWithResponseStream", # Invokes a Bedrock model for inference with real-time token streaming (Read).
"GetUseCaseForModelAccess", # Retrieves an existing use case for model access (Read).
"GetModelInvocationLoggingConfiguration", # Fetches the logging configuration for model invocations (Read).
"GetFoundationModelAvailability", # Checks the availability of a foundation model for use (Read).
"ListFoundationModelAgreementOffers", # Lists available agreement offers for accessing foundation models (List).
"ListFoundationModels", # Lists the available foundation models in Bedrock (List).
"ListProvisionedModelThroughputs", # Lists the provisioned throughput for previously created models (List).
]
# AWS RDS Configuration
# aws.rds_instance_backup_enabled
@@ -334,11 +356,30 @@ aws:
# Minimum number of Availability Zones that an ELBv2 must be in
elbv2_min_azs: 2
# AWS Elasticache Configuration
# aws.elasticache_redis_cluster_backup_enabled
# Minimum number of days that a Redis cluster must have backups retention period
minimum_snapshot_retention_period: 7
# AWS Secrets Configuration
# Patterns to ignore in the secrets checks
secrets_ignore_patterns: []
# AWS Secrets Manager Configuration
# aws.secretsmanager_secret_unused
# Maximum number of days a secret can be unused
max_days_secret_unused: 90
# aws.secretsmanager_secret_rotated_periodically
# Maximum number of days a secret should be rotated
max_days_secret_unrotated: 90
# AWS Kinesis Configuration
# Minimum retention period in hours for Kinesis streams
min_kinesis_stream_retention_hours: 168 # 7 days
# Azure Configuration
azure:
# Azure Network Configuration
+9 -6
View File
@@ -9,14 +9,14 @@ class ProwlerException(Exception):
}
def __init__(
self, code, provider=None, file=None, original_exception=None, error_info=None
self, code, source=None, file=None, original_exception=None, error_info=None
):
"""
Initialize the ProwlerException class.
Args:
code (int): The error code.
provider (str): The provider name.
source (str): The source name. This can be the provider name, module name, service name, etc.
file (str): The file name.
original_exception (Exception): The original exception.
error_info (dict): The error information.
@@ -28,7 +28,7 @@ class ProwlerException(Exception):
>>> [1901] Unexpected error occurred. - Exception: Error occurred.
"""
self.code = code
self.provider = provider
self.source = source
self.file = file
if error_info is None:
error_info = self.ERROR_CODES.get((code, self.__class__.__name__))
@@ -45,9 +45,12 @@ class ProwlerException(Exception):
def __str__(self):
"""Overriding the __str__ method"""
return f"{self.__class__.__name__}[{self.code}]: {self.message} - {self.original_exception}"
default_str = f"{self.__class__.__name__}[{self.code}]: {self.message}"
if self.original_exception:
default_str += f" - {self.original_exception}"
return default_str
class UnexpectedError(ProwlerException):
def __init__(self, provider, file, original_exception=None):
super().__init__(1901, provider, file, original_exception)
def __init__(self, source, file, original_exception=None):
super().__init__(1901, source, file, original_exception)
+3 -30
View File
@@ -1,4 +1,3 @@
import functools
import importlib
import json
import os
@@ -274,7 +273,7 @@ def print_checks(
for check in check_list:
try:
print(
f"[{bulk_checks_metadata[check].CheckID}] {bulk_checks_metadata[check].CheckTitle} - {Fore.MAGENTA}{bulk_checks_metadata[check].ServiceName} {Fore.YELLOW}[{bulk_checks_metadata[check].Severity}]{Style.RESET_ALL}"
f"[{bulk_checks_metadata[check].CheckID}] {bulk_checks_metadata[check].CheckTitle} - {Fore.MAGENTA}{bulk_checks_metadata[check].ServiceName} {Fore.YELLOW}[{bulk_checks_metadata[check].Severity.value}]{Style.RESET_ALL}"
)
except KeyError as error:
logger.error(
@@ -293,32 +292,6 @@ def print_checks(
print(message)
# Parse checks from compliance frameworks specification
def parse_checks_from_compliance_framework(
compliance_frameworks: list, bulk_compliance_frameworks: dict
) -> list:
"""parse_checks_from_compliance_framework returns a set of checks from the given compliance_frameworks"""
checks_to_execute = set()
try:
for framework in compliance_frameworks:
# compliance_framework_json["Requirements"][*]["Checks"]
compliance_framework_checks_list = [
requirement.Checks
for requirement in bulk_compliance_frameworks[framework].Requirements
]
# Reduce nested list into a list
# Pythonic functional magic
compliance_framework_checks = functools.reduce(
lambda x, y: x + y, compliance_framework_checks_list
)
# Then union this list of checks with the initial one
checks_to_execute = checks_to_execute.union(compliance_framework_checks)
except Exception as e:
logger.error(f"{e.__class__.__name__}[{e.__traceback__.tb_lineno}] -- {e}")
return checks_to_execute
# Import an input check using its path
def import_check(check_path: str) -> ModuleType:
lib = importlib.import_module(f"{check_path}")
@@ -469,7 +442,7 @@ def execute_checks(
continue
if verbose:
print(
f"\nCheck ID: {check.CheckID} - {Fore.MAGENTA}{check.ServiceName}{Fore.YELLOW} [{check.Severity}]{Style.RESET_ALL}"
f"\nCheck ID: {check.CheckID} - {Fore.MAGENTA}{check.ServiceName}{Fore.YELLOW} [{check.Severity.value}]{Style.RESET_ALL}"
)
check_findings = execute(
check,
@@ -549,7 +522,7 @@ def execute_checks(
continue
if verbose:
print(
f"\nCheck ID: {check.CheckID} - {Fore.MAGENTA}{check.ServiceName}{Fore.YELLOW} [{check.Severity}]{Style.RESET_ALL}"
f"\nCheck ID: {check.CheckID} - {Fore.MAGENTA}{check.ServiceName}{Fore.YELLOW} [{check.Severity.value}]{Style.RESET_ALL}"
)
check_findings = execute(
check,
+45 -36
View File
@@ -1,37 +1,33 @@
from colorama import Fore, Style
from prowler.config.config import valid_severities
from prowler.lib.check.check import (
parse_checks_from_compliance_framework,
parse_checks_from_file,
)
from prowler.lib.check.utils import (
recover_checks_from_provider,
recover_checks_from_service,
)
from prowler.lib.check.check import parse_checks_from_file
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.check.models import CheckMetadata, Severity
from prowler.lib.logger import logger
# Generate the list of checks to execute
def load_checks_to_execute(
bulk_checks_metadata: dict,
bulk_compliance_frameworks: dict,
checks_file: str,
check_list: list,
service_list: list,
severities: list,
compliance_frameworks: list,
categories: set,
provider: str,
bulk_checks_metadata: dict = None,
bulk_compliance_frameworks: dict = None,
checks_file: str = None,
check_list: list = None,
service_list: list = None,
severities: list = None,
compliance_frameworks: list = None,
categories: set = None,
) -> set:
"""Generate the list of checks to execute based on the cloud provider and the input arguments given"""
try:
# Local subsets
checks_to_execute = set()
check_aliases = {}
check_severities = {key: [] for key in valid_severities}
check_categories = {}
check_severities = {severity.value: [] for severity in Severity}
if not bulk_checks_metadata:
bulk_checks_metadata = CheckMetadata.get_bulk(provider=provider)
# First, loop over the bulk_checks_metadata to extract the needed subsets
for check, metadata in bulk_checks_metadata.items():
try:
@@ -66,24 +62,41 @@ def load_checks_to_execute(
checks_to_execute.update(check_severities[severity])
if service_list:
checks_to_execute = (
recover_checks_from_service(service_list, provider)
& checks_to_execute
)
for service in service_list:
checks_to_execute = (
set(
CheckMetadata.list(
bulk_checks_metadata=bulk_checks_metadata,
service=service,
)
)
& checks_to_execute
)
# Handle if there are checks passed using -C/--checks-file
elif checks_file:
checks_to_execute = parse_checks_from_file(checks_file, provider)
# Handle if there are services passed using -s/--services
elif service_list:
checks_to_execute = recover_checks_from_service(service_list, provider)
for service in service_list:
checks_to_execute.update(
CheckMetadata.list(
bulk_checks_metadata=bulk_checks_metadata,
service=service,
)
)
# Handle if there are compliance frameworks passed using --compliance
elif compliance_frameworks:
checks_to_execute = parse_checks_from_compliance_framework(
compliance_frameworks, bulk_compliance_frameworks
)
if not bulk_compliance_frameworks:
bulk_compliance_frameworks = Compliance.get_bulk(provider=provider)
for compliance_framework in compliance_frameworks:
checks_to_execute.update(
CheckMetadata.list(
bulk_compliance_frameworks=bulk_compliance_frameworks,
compliance_framework=compliance_framework,
)
)
# Handle if there are categories passed using --categories
elif categories:
@@ -92,17 +105,13 @@ def load_checks_to_execute(
# If there are no checks passed as argument
else:
# Get all check modules to run with the specific provider
checks = recover_checks_from_provider(provider)
for check_info in checks:
# Recover check name from import path (last part)
# Format: "providers.{provider}.services.{service}.{check_name}.{check_name}"
check_name = check_info[0]
# get all checks
for check_name in CheckMetadata.list(
bulk_checks_metadata=bulk_checks_metadata
):
checks_to_execute.add(check_name)
# Only execute threat detection checks if threat-detection category is set
if "threat-detection" not in categories:
if not categories or "threat-detection" not in categories:
for threat_detection_check in check_categories.get("threat-detection", []):
checks_to_execute.discard(threat_detection_check)
+1
View File
@@ -83,6 +83,7 @@ class CIS_Requirement_Attribute(BaseModel):
"""CIS Requirement Attribute"""
Section: str
SubSection: Optional[str]
Profile: CIS_Requirement_Attribute_Profile
AssessmentStatus: CIS_Requirement_Attribute_AssessmentStatus
Description: str
+2 -2
View File
@@ -3,7 +3,7 @@ import sys
import yaml
from jsonschema import validate
from prowler.config.config import valid_severities
from prowler.lib.check.models import Severity
from prowler.lib.logger import logger
custom_checks_metadata_schema = {
@@ -17,7 +17,7 @@ custom_checks_metadata_schema = {
"properties": {
"Severity": {
"type": "string",
"enum": valid_severities,
"enum": [severity.value for severity in Severity],
},
"CheckTitle": {
"type": "string",
+223 -10
View File
@@ -1,12 +1,16 @@
import functools
import os
import re
import sys
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from typing import Set
from pydantic import BaseModel, ValidationError, validator
from prowler.config.config import valid_severities
from prowler.config.config import Provider
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.check.utils import recover_checks_from_provider
from prowler.lib.logger import logger
@@ -54,6 +58,14 @@ class Remediation(BaseModel):
Recommendation: Recommendation
class Severity(str, Enum):
critical = "critical"
high = "high"
medium = "medium"
low = "low"
informational = "informational"
class CheckMetadata(BaseModel):
"""
Model representing the metadata of a check.
@@ -93,7 +105,7 @@ class CheckMetadata(BaseModel):
ServiceName: str
SubServiceName: str
ResourceIdTemplate: str
Severity: str
Severity: Severity
ResourceType: str
Description: str
Risk: str
@@ -122,14 +134,6 @@ class CheckMetadata(BaseModel):
def severity_to_lower(severity):
return severity.lower()
@validator("Severity")
def valid_severity(severity):
if severity not in valid_severities:
raise ValueError(
f"Invalid severity: {severity}. Severity must be one of {', '.join(valid_severities)}"
)
return severity
@staticmethod
def get_bulk(provider: str) -> dict[str, "CheckMetadata"]:
"""
@@ -158,6 +162,215 @@ class CheckMetadata(BaseModel):
return bulk_check_metadata
@staticmethod
def list(
bulk_checks_metadata: dict = None,
bulk_compliance_frameworks: dict = None,
provider: str = None,
severity: str = None,
category: str = None,
service: str = None,
compliance_framework: str = None,
) -> Set["CheckMetadata"]:
"""
Returns a set of checks from the bulk checks metadata.
Args:
provider (str): The provider of the checks.
bulk_checks_metadata (dict): The bulk checks metadata.
bulk_compliance_frameworks (dict): The bulk compliance frameworks.
severity (str): The severity of the checks.
category (str): The category of the checks.
service (str): The service of the checks.
compliance_framework (str): The compliance framework of the checks.
Returns:
set: A set of checks.
"""
checks_from_provider = set()
checks_from_severity = set()
checks_from_category = set()
checks_from_service = set()
checks_from_compliance_framework = set()
# If the bulk checks metadata is not provided, get it
if not bulk_checks_metadata:
bulk_checks_metadata = {}
available_providers = [p.value for p in Provider]
for provider_name in available_providers:
bulk_checks_metadata.update(CheckMetadata.get_bulk(provider_name))
if provider:
checks_from_provider = {
check_name
for check_name, check_metadata in bulk_checks_metadata.items()
if check_metadata.Provider == provider
}
if severity:
checks_from_severity = CheckMetadata.list_by_severity(
bulk_checks_metadata=bulk_checks_metadata, severity=severity
)
if category:
checks_from_category = CheckMetadata.list_by_category(
bulk_checks_metadata=bulk_checks_metadata, category=category
)
if service:
checks_from_service = CheckMetadata.list_by_service(
bulk_checks_metadata=bulk_checks_metadata, service=service
)
if compliance_framework:
# Loaded here, as it is not always needed
if not bulk_compliance_frameworks:
bulk_compliance_frameworks = {}
available_providers = [p.value for p in Provider]
for provider in available_providers:
bulk_compliance_frameworks = Compliance.get_bulk(provider=provider)
checks_from_compliance_framework = (
CheckMetadata.list_by_compliance_framework(
bulk_compliance_frameworks=bulk_compliance_frameworks,
compliance_framework=compliance_framework,
)
)
# Get all the checks:
checks = set(bulk_checks_metadata.keys())
# Get the intersection of the checks
if len(checks_from_provider) > 0 or provider:
checks = checks & checks_from_provider
if len(checks_from_severity) > 0 or severity:
checks = checks & checks_from_severity
if len(checks_from_category) > 0 or category:
checks = checks & checks_from_category
if len(checks_from_service) > 0 or service:
checks = checks & checks_from_service
if len(checks_from_compliance_framework) > 0 or compliance_framework:
checks = checks & checks_from_compliance_framework
return checks
@staticmethod
def get(bulk_checks_metadata: dict, check_id: str) -> "CheckMetadata":
"""
Returns the check metadata from the bulk checks metadata.
Args:
bulk_checks_metadata (dict): The bulk checks metadata.
check_id (str): The check ID.
Returns:
CheckMetadata: The check metadata.
"""
return bulk_checks_metadata.get(check_id, None)
@staticmethod
def list_by_severity(bulk_checks_metadata: dict, severity: str = None) -> set:
"""
Returns a set of checks by severity from the bulk checks metadata.
Args:
bulk_checks_metadata (dict): The bulk checks metadata.
severity (str): The severity.
Returns:
set: A set of checks by severity.
"""
checks = set()
if severity:
checks = {
check_name
for check_name, check_metadata in bulk_checks_metadata.items()
if check_metadata.Severity == severity
}
return checks
@staticmethod
def list_by_category(bulk_checks_metadata: dict, category: str = None) -> set:
"""
Returns a set of checks by category from the bulk checks metadata.
Args:
bulk_checks_metadata (dict): The bulk checks metadata.
category (str): The category.
Returns:
set: A set of checks by category.
"""
checks = set()
if category:
checks = {
check_name
for check_name, check_metadata in bulk_checks_metadata.items()
if category in check_metadata.Categories
}
return checks
@staticmethod
def list_by_service(bulk_checks_metadata: dict, service: str = None) -> set:
"""
Returns a set of checks by service from the bulk checks metadata.
Args:
bulk_checks_metadata (dict): The bulk checks metadata.
service (str): The service.
Returns:
set: A set of checks by service.
"""
checks = set()
if service:
# This is a special case for the AWS provider since `lambda` is a reserved keyword in Python
if service == "awslambda":
service = "lambda"
checks = {
check_name
for check_name, check_metadata in bulk_checks_metadata.items()
if check_metadata.ServiceName == service
}
return checks
@staticmethod
def list_by_compliance_framework(
bulk_compliance_frameworks: dict, compliance_framework: str = None
) -> set:
"""
Returns a set of checks by compliance framework from the bulk compliance frameworks.
Args:
bulk_compliance_frameworks (dict): The bulk compliance frameworks.
compliance_framework (str): The compliance framework.
Returns:
set: A set of checks by compliance framework.
"""
checks = set()
if compliance_framework:
try:
checks_from_framework_list = [
requirement.Checks
for requirement in bulk_compliance_frameworks[
compliance_framework
].Requirements
]
# Reduce nested list into a list
# Pythonic functional magic
checks_from_framework = functools.reduce(
lambda x, y: x + y, checks_from_framework_list
)
# Then union this list of checks with the initial one
checks = checks.union(checks_from_framework)
except Exception as e:
logger.error(
f"{e.__class__.__name__}[{e.__traceback__.tb_lineno}] -- {e}"
)
return checks
class Check(ABC, CheckMetadata):
"""Prowler Check"""
+12 -6
View File
@@ -10,9 +10,9 @@ from prowler.config.config import (
default_config_file_path,
default_fixer_config_file_path,
default_output_directory,
finding_statuses,
valid_severities,
)
from prowler.lib.check.models import Severity
from prowler.lib.outputs.common import Status
from prowler.providers.common.arguments import (
init_providers_parser,
validate_provider_arguments,
@@ -138,8 +138,8 @@ Detailed documentation at https://docs.prowler.com
common_outputs_parser.add_argument(
"--status",
nargs="+",
help=f"Filter by the status of the findings {finding_statuses}",
choices=finding_statuses,
help=f"Filter by the status of the findings {[status.value for status in Status]}",
choices=[status.value for status in Status],
)
common_outputs_parser.add_argument(
"--output-formats",
@@ -177,6 +177,12 @@ Detailed documentation at https://docs.prowler.com
common_outputs_parser.add_argument(
"--no-banner", "-b", action="store_true", help="Hide Prowler banner"
)
common_outputs_parser.add_argument(
"--no-color",
action="store_true",
help="Disable color codes in output",
)
common_outputs_parser.add_argument(
"--unix-timestamp",
action="store_true",
@@ -257,8 +263,8 @@ Detailed documentation at https://docs.prowler.com
"--severity",
"--severities",
nargs="+",
help=f"Severities to be executed {valid_severities}",
choices=valid_severities,
help=f"Severities to be executed {[severity.value for severity in Severity]}",
choices=[severity.value for severity in Severity],
)
group.add_argument(
"--compliance",
+31
View File
@@ -5,6 +5,8 @@ import yaml
from prowler.lib.logger import logger
from prowler.lib.mutelist.models import mutelist_schema
from prowler.lib.outputs.common import Status
from prowler.lib.outputs.utils import unroll_dict, unroll_tags
class Mutelist(ABC):
@@ -237,6 +239,35 @@ class Mutelist(ABC):
)
return False
def mute_finding(self, finding):
"""
Check if the provided finding is muted
Args:
finding (Finding): The finding to be evaluated for muting.
Returns:
Finding: The finding with the status updated if it is muted, otherwise the finding is returned
"""
try:
if self.is_muted(
finding.account_uid,
finding.metadata.CheckID,
finding.region,
finding.resource_uid,
unroll_dict(unroll_tags(finding.resource_tags)),
):
finding.raw["status"] = finding.status
finding.status = Status.MUTED
finding.muted = True
return finding
except Exception as error:
logger.error(
f"{error.__class__.__name__} -- {error}[{error.__traceback__.tb_lineno}]"
)
return finding
def is_excepted(
self,
exceptions,
+9 -9
View File
@@ -72,23 +72,23 @@ class ASFF(Output):
AWSSecurityFindingFormat(
# The following line cannot be changed because it is the format we use to generate unique findings for AWS Security Hub
# If changed some findings could be lost because the unique identifier will be different
Id=f"prowler-{finding.check_id}-{finding.account_uid}-{finding.region}-{hash_sha512(finding.resource_uid)}",
Id=f"prowler-{finding.metadata.CheckID}-{finding.account_uid}-{finding.region}-{hash_sha512(finding.resource_uid)}",
ProductArn=f"arn:{finding.partition}:securityhub:{finding.region}::product/prowler/prowler",
ProductFields=ProductFields(
ProwlerResourceName=finding.resource_uid,
),
GeneratorId="prowler-" + finding.check_id,
GeneratorId="prowler-" + finding.metadata.CheckID,
AwsAccountId=finding.account_uid,
Types=(
finding.check_type.split(",")
if finding.check_type
finding.metadata.CheckType
if finding.metadata.CheckType
else ["Software and Configuration Checks"]
),
FirstObservedAt=timestamp,
UpdatedAt=timestamp,
CreatedAt=timestamp,
Severity=Severity(Label=finding.severity.value),
Title=finding.check_title,
Severity=Severity(Label=finding.metadata.Severity.value),
Title=finding.metadata.CheckTitle,
Description=(
(finding.status_extended[:1000] + "...")
if len(finding.status_extended) > 1000
@@ -97,7 +97,7 @@ class ASFF(Output):
Resources=[
Resource(
Id=finding.resource_uid,
Type=finding.resource_type,
Type=finding.metadata.ResourceType,
Partition=finding.partition,
Region=finding.region,
Tags=finding.resource_tags,
@@ -110,8 +110,8 @@ class ASFF(Output):
),
Remediation=Remediation(
Recommendation=Recommendation(
Text=finding.remediation_recommendation_text,
Url=finding.remediation_recommendation_url,
Text=finding.metadata.Remediation.Recommendation.Text,
Url=finding.metadata.Remediation.Recommendation.Url,
)
),
)
+10 -46
View File
@@ -1,62 +1,26 @@
from operator import attrgetter
from enum import Enum
from prowler.config.config import timestamp
from prowler.lib.logger import logger
from prowler.lib.outputs.utils import unroll_list, unroll_tags
from prowler.lib.outputs.utils import unroll_tags
from prowler.lib.utils.utils import outputs_unix_timestamp
def get_provider_data_mapping(provider) -> dict:
data = {}
for generic_field, provider_field in provider.get_output_mapping.items():
try:
provider_value = attrgetter(provider_field)(provider)
data[generic_field] = provider_value
except AttributeError:
data[generic_field] = ""
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return data
# TODO: add test for outputs_unix_timestamp
def fill_common_finding_data(finding: dict, unix_timestamp: bool) -> dict:
finding_data = {
"metadata": finding.check_metadata,
"timestamp": outputs_unix_timestamp(unix_timestamp, timestamp),
"check_id": finding.check_metadata.CheckID,
"check_title": finding.check_metadata.CheckTitle,
"check_type": ",".join(finding.check_metadata.CheckType),
"status": finding.status,
"status_extended": finding.status_extended,
"muted": finding.muted,
"service_name": finding.check_metadata.ServiceName,
"subservice_name": finding.check_metadata.SubServiceName,
"severity": finding.check_metadata.Severity,
"resource_type": finding.check_metadata.ResourceType,
"resource_details": finding.resource_details,
"resource_tags": unroll_tags(finding.resource_tags),
"description": finding.check_metadata.Description,
"risk": finding.check_metadata.Risk,
"related_url": finding.check_metadata.RelatedUrl,
"remediation_recommendation_text": (
finding.check_metadata.Remediation.Recommendation.Text
),
"remediation_recommendation_url": (
finding.check_metadata.Remediation.Recommendation.Url
),
"remediation_code_nativeiac": (
finding.check_metadata.Remediation.Code.NativeIaC
),
"remediation_code_terraform": (
finding.check_metadata.Remediation.Code.Terraform
),
"remediation_code_cli": (finding.check_metadata.Remediation.Code.CLI),
"remediation_code_other": (finding.check_metadata.Remediation.Code.Other),
"categories": unroll_list(finding.check_metadata.Categories),
"depends_on": unroll_list(finding.check_metadata.DependsOn),
"related_to": unroll_list(finding.check_metadata.RelatedTo),
"notes": finding.check_metadata.Notes,
}
return finding_data
class Status(str, Enum):
PASS = "PASS"
FAIL = "FAIL"
MANUAL = "MANUAL"
MUTED = "MUTED"
+4 -3
View File
@@ -94,11 +94,12 @@ def get_cis_table(
print(
f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:"
)
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
overview_table = [
[
f"{Fore.RED}{round(len(fail_count) / len(findings) * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / len(findings) * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / len(findings) * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
]
]
print(tabulate(overview_table, tablefmt="rounded_grid"))
@@ -48,6 +48,7 @@ class AWSCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -78,6 +79,7 @@ class AWSCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -42,12 +42,13 @@ class AzureCIS(ComplianceOutput):
compliance_row = AzureCISModel(
Provider=finding.provider,
Description=compliance.Description,
Subscription=finding.account_name,
SubscriptionId=finding.account_uid,
Location=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -73,12 +74,13 @@ class AzureCIS(ComplianceOutput):
compliance_row = AzureCISModel(
Provider=compliance.Provider.lower(),
Description=compliance.Description,
Subscription="",
SubscriptionId="",
Location="",
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -48,6 +48,7 @@ class GCPCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -78,6 +79,7 @@ class GCPCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -50,6 +50,7 @@ class KubernetesCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -81,6 +82,7 @@ class KubernetesCIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
+7 -1
View File
@@ -1,3 +1,5 @@
from typing import Optional
from pydantic import BaseModel
@@ -14,6 +16,7 @@ class AWSCISModel(BaseModel):
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_SubSection: Optional[str]
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
@@ -38,12 +41,13 @@ class AzureCISModel(BaseModel):
Provider: str
Description: str
Subscription: str
SubscriptionId: str
Location: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_SubSection: Optional[str]
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
@@ -75,6 +79,7 @@ class GCPCISModel(BaseModel):
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_SubSection: Optional[str]
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
@@ -105,6 +110,7 @@ class KubernetesCISModel(BaseModel):
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_SubSection: Optional[str]
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
+5 -4
View File
@@ -30,7 +30,7 @@ def get_ens_table(
check = bulk_checks_metadata[finding.check_metadata.CheckID]
check_compliances = check.Compliance
for compliance in check_compliances:
if compliance.Framework == "ENS" and compliance.Provider == "AWS":
if compliance.Framework == "ENS":
for requirement in compliance.Requirements:
for attribute in requirement.Attributes:
marco_categoria = f"{attribute.Marco}/{attribute.Categoria}"
@@ -95,11 +95,12 @@ def get_ens_table(
print(
f"\nEstado de Cumplimiento de {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL}:"
)
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
overview_table = [
[
f"{Fore.RED}{round(len(fail_count) / len(findings) * 100, 2)}% ({len(fail_count)}) NO CUMPLE{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / len(findings) * 100, 2)}% ({len(pass_count)}) CUMPLE{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / len(findings) * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) NO CUMPLE{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) CUMPLE{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
]
]
print(tabulate(overview_table, tablefmt="rounded_grid"))
@@ -0,0 +1,103 @@
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.compliance.ens.models import AzureENSModel
from prowler.lib.outputs.finding import Finding
class AzureENS(ComplianceOutput):
"""
This class represents the Azure ENS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into Azure ENS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: Compliance,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into AWS ENS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (Compliance): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = AzureENSModel(
Provider=finding.provider,
Description=compliance.Description,
SubscriptionId=finding.account_name,
Location=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_IdGrupoControl=attribute.IdGrupoControl,
Requirements_Attributes_Marco=attribute.Marco,
Requirements_Attributes_Categoria=attribute.Categoria,
Requirements_Attributes_DescripcionControl=attribute.DescripcionControl,
Requirements_Attributes_Nivel=attribute.Nivel,
Requirements_Attributes_Tipo=attribute.Tipo,
Requirements_Attributes_Dimensiones=",".join(
attribute.Dimensiones
),
Requirements_Attributes_ModoEjecucion=attribute.ModoEjecucion,
Requirements_Attributes_Dependencias=",".join(
attribute.Dependencias
),
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
ResourceName=finding.resource_name,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
# Add manual requirements to the compliance output
for requirement in compliance.Requirements:
if not requirement.Checks:
for attribute in requirement.Attributes:
compliance_row = AzureENSModel(
Provider=compliance.Provider.lower(),
Description=compliance.Description,
SubscriptionId="",
Location="",
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_IdGrupoControl=attribute.IdGrupoControl,
Requirements_Attributes_Marco=attribute.Marco,
Requirements_Attributes_Categoria=attribute.Categoria,
Requirements_Attributes_DescripcionControl=attribute.DescripcionControl,
Requirements_Attributes_Nivel=attribute.Nivel,
Requirements_Attributes_Tipo=attribute.Tipo,
Requirements_Attributes_Dimensiones=",".join(
attribute.Dimensiones
),
Requirements_Attributes_ModoEjecucion=attribute.ModoEjecucion,
Requirements_Attributes_Dependencias=",".join(
attribute.Dependencias
),
Status="MANUAL",
StatusExtended="Manual check",
ResourceId="manual_check",
ResourceName="Manual check",
CheckId="manual",
Muted=False,
)
self._data.append(compliance_row)
@@ -0,0 +1,103 @@
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.outputs.compliance.compliance_output import ComplianceOutput
from prowler.lib.outputs.compliance.ens.models import GCPENSModel
from prowler.lib.outputs.finding import Finding
class GCPENS(ComplianceOutput):
"""
This class represents the GCP ENS compliance output.
Attributes:
- _data (list): A list to store transformed data from findings.
- _file_descriptor (TextIOWrapper): A file descriptor to write data to a file.
Methods:
- transform: Transforms findings into GCP ENS compliance format.
"""
def transform(
self,
findings: list[Finding],
compliance: Compliance,
compliance_name: str,
) -> None:
"""
Transforms a list of findings into AWS ENS compliance format.
Parameters:
- findings (list): A list of findings.
- compliance (Compliance): A compliance model.
- compliance_name (str): The name of the compliance model.
Returns:
- None
"""
for finding in findings:
# Get the compliance requirements for the finding
finding_requirements = finding.compliance.get(compliance_name, [])
for requirement in compliance.Requirements:
if requirement.Id in finding_requirements:
for attribute in requirement.Attributes:
compliance_row = GCPENSModel(
Provider=finding.provider,
Description=compliance.Description,
ProjectId=finding.account_uid,
Location=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_IdGrupoControl=attribute.IdGrupoControl,
Requirements_Attributes_Marco=attribute.Marco,
Requirements_Attributes_Categoria=attribute.Categoria,
Requirements_Attributes_DescripcionControl=attribute.DescripcionControl,
Requirements_Attributes_Nivel=attribute.Nivel,
Requirements_Attributes_Tipo=attribute.Tipo,
Requirements_Attributes_Dimensiones=",".join(
attribute.Dimensiones
),
Requirements_Attributes_ModoEjecucion=attribute.ModoEjecucion,
Requirements_Attributes_Dependencias=",".join(
attribute.Dependencias
),
Status=finding.status,
StatusExtended=finding.status_extended,
ResourceId=finding.resource_uid,
ResourceName=finding.resource_name,
CheckId=finding.check_id,
Muted=finding.muted,
)
self._data.append(compliance_row)
# Add manual requirements to the compliance output
for requirement in compliance.Requirements:
if not requirement.Checks:
for attribute in requirement.Attributes:
compliance_row = GCPENSModel(
Provider=compliance.Provider.lower(),
Description=compliance.Description,
ProjectId="",
Location="",
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_IdGrupoControl=attribute.IdGrupoControl,
Requirements_Attributes_Marco=attribute.Marco,
Requirements_Attributes_Categoria=attribute.Categoria,
Requirements_Attributes_DescripcionControl=attribute.DescripcionControl,
Requirements_Attributes_Nivel=attribute.Nivel,
Requirements_Attributes_Tipo=attribute.Tipo,
Requirements_Attributes_Dimensiones=",".join(
attribute.Dimensiones
),
Requirements_Attributes_ModoEjecucion=attribute.ModoEjecucion,
Requirements_Attributes_Dependencias=",".join(
attribute.Dependencias
),
Status="MANUAL",
StatusExtended="Manual check",
ResourceId="manual_check",
ResourceName="Manual check",
CheckId="manual",
Muted=False,
)
self._data.append(compliance_row)
@@ -28,3 +28,61 @@ class AWSENSModel(BaseModel):
CheckId: str
Muted: bool
ResourceName: str
class AzureENSModel(BaseModel):
"""
AzureENSModel generates a finding's output in CSV ENS format for Azure.
"""
Provider: str
Description: str
SubscriptionId: str
Location: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_IdGrupoControl: str
Requirements_Attributes_Marco: str
Requirements_Attributes_Categoria: str
Requirements_Attributes_DescripcionControl: str
Requirements_Attributes_Nivel: str
Requirements_Attributes_Tipo: str
Requirements_Attributes_Dimensiones: str
Requirements_Attributes_ModoEjecucion: str
Requirements_Attributes_Dependencias: str
Status: str
StatusExtended: str
ResourceId: str
CheckId: str
Muted: bool
ResourceName: str
class GCPENSModel(BaseModel):
"""
GCPENSModel generates a finding's output in CSV ENS format for GCP.
"""
Provider: str
Description: str
ProjectId: str
Location: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_IdGrupoControl: str
Requirements_Attributes_Marco: str
Requirements_Attributes_Categoria: str
Requirements_Attributes_DescripcionControl: str
Requirements_Attributes_Nivel: str
Requirements_Attributes_Tipo: str
Requirements_Attributes_Dimensiones: str
Requirements_Attributes_ModoEjecucion: str
Requirements_Attributes_Dependencias: str
Status: str
StatusExtended: str
ResourceId: str
CheckId: str
Muted: bool
ResourceName: str
@@ -39,11 +39,12 @@ def get_generic_compliance_table(
print(
f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:"
)
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
overview_table = [
[
f"{Fore.RED}{round(len(fail_count) / len(findings) * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / len(findings) * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / len(findings) * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
]
]
print(tabulate(overview_table, tablefmt="rounded_grid"))
@@ -45,6 +45,8 @@ class AWSISO27001(ComplianceOutput):
AccountId=finding.account_uid,
Region=finding.region,
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Category=attribute.Category,
Requirements_Attributes_Objetive_ID=attribute.Objetive_ID,
Requirements_Attributes_Objetive_Name=attribute.Objetive_Name,
@@ -67,6 +69,8 @@ class AWSISO27001(ComplianceOutput):
AccountId="",
Region="",
AssessmentDate=str(finding.timestamp),
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Category=attribute.Category,
Requirements_Attributes_Objetive_ID=attribute.Objetive_ID,
Requirements_Attributes_Objetive_Name=attribute.Objetive_Name,
@@ -11,6 +11,8 @@ class AWSISO27001Model(BaseModel):
AccountId: str
Region: str
AssessmentDate: str
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Category: str
Requirements_Attributes_Objetive_ID: str
Requirements_Attributes_Objetive_Name: str
@@ -61,11 +61,12 @@ def get_kisa_ismsp_table(
print(
f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:"
)
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
overview_table = [
[
f"{Fore.RED}{round(len(fail_count) / len(findings) * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / len(findings) * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / len(findings) * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
]
]
print(tabulate(overview_table, tablefmt="rounded_grid"))
@@ -69,11 +69,12 @@ def get_mitre_attack_table(
print(
f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:"
)
total_findings_count = len(fail_count) + len(pass_count) + len(muted_count)
overview_table = [
[
f"{Fore.RED}{round(len(fail_count) / len(findings) * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / len(findings) * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / len(findings) * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}",
f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}",
f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}",
]
]
print(tabulate(overview_table, tablefmt="rounded_grid"))
+60 -7
View File
@@ -1,13 +1,14 @@
from csv import DictWriter
from typing import List
from prowler.lib.logger import logger
from prowler.lib.outputs.finding import Finding
from prowler.lib.outputs.output import Output
from prowler.lib.outputs.utils import unroll_dict
from prowler.lib.outputs.utils import unroll_dict, unroll_list
class CSV(Output):
def transform(self, findings: list[Finding]) -> None:
def transform(self, findings: List[Finding]) -> None:
"""Transforms the findings into the CSV format.
Args:
@@ -16,16 +17,68 @@ class CSV(Output):
"""
try:
for finding in findings:
finding_dict = {k.upper(): v for k, v in finding.dict().items()}
finding_dict["RESOURCE_TAGS"] = unroll_dict(finding.resource_tags)
finding_dict["COMPLIANCE"] = unroll_dict(
finding.compliance, separator=": "
finding_dict = {}
finding_dict["AUTH_METHOD"] = finding.auth_method
finding_dict["TIMESTAMP"] = finding.timestamp
finding_dict["ACCOUNT_UID"] = finding.account_uid
finding_dict["ACCOUNT_NAME"] = finding.account_name
finding_dict["ACCOUNT_EMAIL"] = finding.account_email
finding_dict["ACCOUNT_ORGANIZATION_UID"] = (
finding.account_organization_uid
)
finding_dict["ACCOUNT_ORGANIZATION_NAME"] = (
finding.account_organization_name
)
finding_dict["ACCOUNT_TAGS"] = unroll_dict(
finding.account_tags, separator=":"
)
finding_dict["FINDING_UID"] = finding.uid
finding_dict["PROVIDER"] = finding.metadata.Provider
finding_dict["CHECK_ID"] = finding.metadata.CheckID
finding_dict["CHECK_TITLE"] = finding.metadata.CheckTitle
finding_dict["CHECK_TYPE"] = unroll_list(finding.metadata.CheckType)
finding_dict["STATUS"] = finding.status.value
finding_dict["SEVERITY"] = finding.severity.value
finding_dict["STATUS_EXTENDED"] = finding.status_extended
finding_dict["MUTED"] = finding.muted
finding_dict["SERVICE_NAME"] = finding.metadata.ServiceName
finding_dict["SUBSERVICE_NAME"] = finding.metadata.SubServiceName
finding_dict["SEVERITY"] = finding.metadata.Severity.value
finding_dict["RESOURCE_TYPE"] = finding.metadata.ResourceType
finding_dict["RESOURCE_UID"] = finding.resource_uid
finding_dict["RESOURCE_NAME"] = finding.resource_name
finding_dict["RESOURCE_DETAILS"] = finding.resource_details
finding_dict["RESOURCE_TAGS"] = unroll_dict(finding.resource_tags)
finding_dict["PARTITION"] = finding.partition
finding_dict["REGION"] = finding.region
finding_dict["DESCRIPTION"] = finding.metadata.Description
finding_dict["RISK"] = finding.metadata.Risk
finding_dict["RELATED_URL"] = finding.metadata.RelatedUrl
finding_dict["REMEDIATION_RECOMMENDATION_TEXT"] = (
finding.metadata.Remediation.Recommendation.Text
)
finding_dict["REMEDIATION_RECOMMENDATION_URL"] = (
finding.metadata.Remediation.Recommendation.Url
)
finding_dict["REMEDIATION_CODE_NATIVEIAC"] = (
finding.metadata.Remediation.Code.NativeIaC
)
finding_dict["REMEDIATION_CODE_TERRAFORM"] = (
finding.metadata.Remediation.Code.Terraform
)
finding_dict["REMEDIATION_CODE_CLI"] = (
finding.metadata.Remediation.Code.CLI
)
finding_dict["REMEDIATION_CODE_OTHER"] = (
finding.metadata.Remediation.Code.Other
)
finding_dict["COMPLIANCE"] = unroll_dict(
finding.compliance, separator=": "
)
finding_dict["CATEGORIES"] = unroll_list(finding.metadata.Categories)
finding_dict["DEPENDS_ON"] = unroll_list(finding.metadata.DependsOn)
finding_dict["RELATED_TO"] = unroll_list(finding.metadata.RelatedTo)
finding_dict["NOTES"] = finding.metadata.Notes
finding_dict["PROWLER_VERSION"] = finding.prowler_version
self._data.append(finding_dict)
except Exception as error:
logger.error(
+111 -66
View File
@@ -1,34 +1,17 @@
from datetime import datetime
from enum import Enum
from typing import Optional, Union
from pydantic import BaseModel
from pydantic import BaseModel, Field
from prowler.config.config import prowler_version
from prowler.lib.check.models import Check_Report
from prowler.lib.check.models import Check_Report, CheckMetadata
from prowler.lib.logger import logger
from prowler.lib.outputs.common import (
fill_common_finding_data,
get_provider_data_mapping,
)
from prowler.lib.outputs.common import Status, fill_common_finding_data
from prowler.lib.outputs.compliance.compliance import get_check_compliance
from prowler.lib.utils.utils import dict_to_lowercase, get_nested_attribute
from prowler.providers.common.provider import Provider
class Status(str, Enum):
PASS = "PASS"
FAIL = "FAIL"
MANUAL = "MANUAL"
class Severity(str, Enum):
critical = "critical"
high = "high"
medium = "medium"
low = "low"
informational = "informational"
class Finding(BaseModel):
"""
Represents the output model for a finding across different providers.
@@ -41,50 +24,69 @@ class Finding(BaseModel):
auth_method: str
timestamp: Union[int, datetime]
account_uid: str
# Optional since it depends on permissions
account_name: Optional[str]
# Optional since it depends on permissions
account_email: Optional[str]
# Optional since it depends on permissions
account_organization_uid: Optional[str]
# Optional since it depends on permissions
account_organization_name: Optional[str]
# Optional since it depends on permissions
account_name: Optional[str] = None
account_email: Optional[str] = None
account_organization_uid: Optional[str] = None
account_organization_name: Optional[str] = None
metadata: CheckMetadata
account_tags: dict = {}
finding_uid: str
provider: str
check_id: str
check_title: str
check_type: str
uid: str
status: Status
status_extended: str
muted: bool = False
service_name: str
subservice_name: str
severity: Severity
resource_type: str
resource_uid: str
resource_name: str
resource_details: str
resource_tags: dict = {}
# Only present for AWS and Azure
partition: Optional[str]
resource_tags: dict = Field(default_factory=dict)
partition: Optional[str] = None
region: str
description: str
risk: str
related_url: str
remediation_recommendation_text: str
remediation_recommendation_url: str
remediation_code_nativeiac: str
remediation_code_terraform: str
remediation_code_cli: str
remediation_code_other: str
compliance: dict
categories: str
depends_on: str
related_to: str
notes: str
prowler_version: str = prowler_version
raw: dict = Field(default_factory=dict)
@property
def provider(self) -> str:
"""
Returns the provider from the finding check's metadata.
"""
return self.metadata.Provider
@property
def check_id(self) -> str:
"""
Returns the ID from the finding check's metadata.
"""
return self.metadata.CheckID
@property
def severity(self) -> str:
"""
Returns the severity from the finding check's metadata.
"""
return self.metadata.Severity
@property
def resource_type(self) -> str:
"""
Returns the resource type from the finding check's metadata.
"""
return self.metadata.ResourceType
@property
def service_name(self) -> str:
"""
Returns the service name from the finding check's metadata.
"""
return self.metadata.ServiceName
def get_metadata(self) -> dict:
"""
Retrieves the metadata of the object and returns it as a dictionary with all keys in lowercase.
Returns:
dict: A dictionary containing the metadata with keys converted to lowercase.
"""
return dict_to_lowercase(self.metadata.dict())
@classmethod
def generate_output(
@@ -100,9 +102,6 @@ class Finding(BaseModel):
finding_output (Finding): the finding output object
"""
# TODO: think about get_provider_data_mapping
provider_data_mapping = get_provider_data_mapping(provider)
# TODO: move fill_common_finding_data
unix_timestamp = False
if hasattr(output_options, "unix_timestamp"):
@@ -110,7 +109,6 @@ class Finding(BaseModel):
common_finding_data = fill_common_finding_data(check_output, unix_timestamp)
output_data = {}
output_data.update(provider_data_mapping)
output_data.update(common_finding_data)
bulk_checks_metadata = {}
@@ -121,9 +119,35 @@ class Finding(BaseModel):
check_output, provider.type, bulk_checks_metadata
)
try:
output_data["provider"] = provider.type
if provider.type == "aws":
output_data["account_uid"] = get_nested_attribute(
provider, "identity.account"
)
output_data["account_name"] = get_nested_attribute(
provider, "organizations_metadata.account_name"
)
output_data["account_email"] = get_nested_attribute(
provider, "organizations_metadata.account_email"
)
output_data["account_organization_uid"] = get_nested_attribute(
provider, "organizations_metadata.organization_arn"
)
output_data["account_organization_name"] = get_nested_attribute(
provider, "organizations_metadata.organization_id"
)
output_data["account_tags"] = get_nested_attribute(
provider, "organizations_metadata.account_tags"
)
output_data["partition"] = get_nested_attribute(
provider, "identity.partition"
)
# TODO: probably Organization UID is without the account id
output_data["auth_method"] = f"profile: {output_data['auth_method']}"
output_data["auth_method"] = (
f"profile: {get_nested_attribute(provider, 'identity.profile')}"
)
output_data["resource_name"] = check_output.resource_id
output_data["resource_uid"] = check_output.resource_arn
output_data["region"] = check_output.region
@@ -134,9 +158,9 @@ class Finding(BaseModel):
f"{provider.identity.identity_type}: {provider.identity.identity_id}"
)
# Get the first tenant domain ID, just in case
output_data["account_organization_uid"] = output_data[
"account_organization_uid"
][0]
output_data["account_organization_uid"] = get_nested_attribute(
provider, "identity.tenant_ids"
)[0]
output_data["account_uid"] = (
output_data["account_organization_uid"]
if "Tenant:" in check_output.subscription
@@ -146,15 +170,33 @@ class Finding(BaseModel):
output_data["resource_name"] = check_output.resource_name
output_data["resource_uid"] = check_output.resource_id
output_data["region"] = check_output.location
# TODO: check the tenant_ids
# TODO: we have to get the account organization, the tenant is not that
output_data["account_organization_name"] = get_nested_attribute(
provider, "identity.tenant_domain"
)
output_data["partition"] = get_nested_attribute(
provider, "region_config.name"
)
# TODO: pending to get the subscription tags
# "account_tags": "organizations_metadata.account_details_tags",
# TODO: store subscription_name + id pairs
# "account_name": "organizations_metadata.account_details_name",
# "account_email": "organizations_metadata.account_details_email",
elif provider.type == "gcp":
output_data["auth_method"] = f"Principal: {output_data['auth_method']}"
output_data["auth_method"] = (
f"Principal: {get_nested_attribute(provider, 'identity.profile')}"
)
output_data["account_uid"] = provider.projects[
check_output.project_id
].id
output_data["account_name"] = provider.projects[
check_output.project_id
].name
# There is no concept as project email in GCP
# "account_email": "organizations_metadata.account_details_email",
output_data["account_tags"] = provider.projects[
check_output.project_id
].labels
@@ -173,7 +215,7 @@ class Finding(BaseModel):
check_output.project_id
].organization.id
# TODO: for now is None since we don't retrieve that data
output_data["account_organization"] = provider.projects[
output_data["account_organization_name"] = provider.projects[
check_output.project_id
].organization.display_name
@@ -185,12 +227,15 @@ class Finding(BaseModel):
output_data["resource_name"] = check_output.resource_name
output_data["resource_uid"] = check_output.resource_id
output_data["account_name"] = f"context: {provider.identity.context}"
output_data["account_uid"] = get_nested_attribute(
provider, "identity.cluster"
)
output_data["region"] = f"namespace: {check_output.namespace}"
# check_output Unique ID
# TODO: move this to a function
# TODO: in Azure, GCP and K8s there are fidings without resource_name
output_data["finding_uid"] = (
output_data["uid"] = (
f"prowler-{provider.type}-{check_output.check_metadata.CheckID}-{output_data['account_uid']}-"
f"{output_data['region']}-{output_data['resource_name']}"
)
+6 -6
View File
@@ -39,16 +39,16 @@ class HTML(Output):
f"""
<tr class="{row_class}">
<td>{finding_status}</td>
<td>{finding.severity.value}</td>
<td>{finding.service_name}</td>
<td>{finding.metadata.Severity.value}</td>
<td>{finding.metadata.ServiceName}</td>
<td>{finding.region.lower()}</td>
<td>{finding.check_id.replace("_", "<wbr />_")}</td>
<td>{finding.check_title}</td>
<td>{finding.metadata.CheckID.replace("_", "<wbr />_")}</td>
<td>{finding.metadata.CheckTitle}</td>
<td>{finding.resource_uid.replace("<", "&lt;").replace(">", "&gt;").replace("_", "<wbr />_")}</td>
<td>{parse_html_string(unroll_dict(finding.resource_tags))}</td>
<td>{finding.status_extended.replace("<", "&lt;").replace(">", "&gt;").replace("_", "<wbr />_")}</td>
<td><p class="show-read-more">{html.escape(finding.risk)}</p></td>
<td><p class="show-read-more">{html.escape(finding.remediation_recommendation_text)}</p> <a class="read-more" href="{finding.remediation_recommendation_url}"><i class="fas fa-external-link-alt"></i></a></td>
<td><p class="show-read-more">{html.escape(finding.metadata.Risk)}</p></td>
<td><p class="show-read-more">{html.escape(finding.metadata.Remediation.Recommendation.Text)}</p> <a class="read-more" href="{finding.metadata.Remediation.Recommendation.Url}"><i class="fas fa-external-link-alt"></i></a></td>
<td><p class="show-read-more">{parse_html_string(unroll_dict(finding.compliance, separator=": "))}</p></td>
</tr>
"""
@@ -0,0 +1,231 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 9000 to 9999 are reserved for Jira exceptions
class JiraBaseException(ProwlerException):
"""Base class for Jira exceptions."""
JIRA_ERROR_CODES = {
(9000, "JiraNoProjectsError"): {
"message": "No projects were found in Jira.",
"remediation": "Please create a project in Jira.",
},
(9001, "JiraAuthenticationError"): {
"message": "Failed to authenticate with Jira.",
"remediation": "Please check the connection settings and permissions and try again. Needed scopes are: read:jira-user read:jira-work write:jira-work",
},
(9002, "JiraTestConnectionError"): {
"message": "Failed to connect to Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9003, "JiraCreateIssueError"): {
"message": "Failed to create an issue in Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9004, "JiraGetProjectsError"): {
"message": "Failed to get projects from Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9005, "JiraGetCloudIDError"): {
"message": "Failed to get the cloud ID from Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9006, "JiraGetCloudIDNoResourcesError"): {
"message": "No resources were found in Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9007, "JiraGetCloudIDResponseError"): {
"message": "Failed to get the cloud ID from Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9008, "JiraRefreshTokenResponseError"): {
"message": "Failed to refresh the access token, response code did not match 200.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9009, "JiraRefreshTokenError"): {
"message": "Failed to refresh the access token.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9010, "JiraGetAccessTokenError"): {
"message": "Failed to get the access token.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9011, "JiraGetAuthResponseError"): {
"message": "Failed to authenticate with Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9012, "JiraGetProjectsResponseError"): {
"message": "Failed to get projects from Jira, response code did not match 200.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9013, "JiraSendFindingsResponseError"): {
"message": "Failed to send findings to Jira, response code did not match 201.",
"remediation": "Please check the finding format and try again.",
},
(9014, "JiraGetAvailableIssueTypesError"): {
"message": "Failed to get available issue types from Jira.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9015, "JiraGetAvailableIssueTypesResponseError"): {
"message": "Failed to get available issue types from Jira, response code did not match 200.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(9016, "JiraInvalidIssueTypeError"): {
"message": "The issue type is invalid.",
"remediation": "Please check the issue type and try again.",
},
(9017, "JiraNoTokenError"): {
"message": "No token was found.",
"remediation": "Make sure the token is set when using the Jira integration.",
},
(9018, "JiraInvalidProjectKeyError"): {
"message": "The project key is invalid.",
"remediation": "Please check the project key and try again.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
module = "Jira"
error_info = self.JIRA_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code=code,
source=module,
file=file,
original_exception=original_exception,
error_info=error_info,
)
class JiraNoProjectsError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9000, file=file, original_exception=original_exception, message=message
)
class JiraAuthenticationError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9001, file=file, original_exception=original_exception, message=message
)
class JiraTestConnectionError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9002, file=file, original_exception=original_exception, message=message
)
class JiraCreateIssueError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9003, file=file, original_exception=original_exception, message=message
)
class JiraGetProjectsError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9004, file=file, original_exception=original_exception, message=message
)
class JiraGetCloudIDError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9005, file=file, original_exception=original_exception, message=message
)
class JiraGetCloudIDNoResourcesError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9006, file=file, original_exception=original_exception, message=message
)
class JiraGetCloudIDResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9007, file=file, original_exception=original_exception, message=message
)
class JiraRefreshTokenResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9008, file=file, original_exception=original_exception, message=message
)
class JiraRefreshTokenError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9009, file=file, original_exception=original_exception, message=message
)
class JiraGetAccessTokenError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9010, file=file, original_exception=original_exception, message=message
)
class JiraGetAuthResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9011, file=file, original_exception=original_exception, message=message
)
class JiraGetProjectsResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9012, file=file, original_exception=original_exception, message=message
)
class JiraSendFindingsResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9013, file=file, original_exception=original_exception, message=message
)
class JiraGetAvailableIssueTypesError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9014, file=file, original_exception=original_exception, message=message
)
class JiraGetAvailableIssueTypesResponseError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9015, file=file, original_exception=original_exception, message=message
)
class JiraInvalidIssueTypeError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9016, file=file, original_exception=original_exception, message=message
)
class JiraNoTokenError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9017, file=file, original_exception=original_exception, message=message
)
class JiraInvalidProjectKeyError(JiraBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
9018, file=file, original_exception=original_exception, message=message
)
File diff suppressed because it is too large. Load diff
+38 -27
View File
@@ -1,4 +1,5 @@
import os
from datetime import datetime
from typing import List
from py_ocsf_models.events.base_event import SeverityID, StatusID
@@ -53,10 +54,12 @@ class OCSF(Output):
for finding in findings:
finding_activity = ActivityID.Create
cloud_account_type = self.get_account_type_id_by_provider(
finding.provider
finding.metadata.Provider
)
finding_severity = getattr(
SeverityID, finding.severity.capitalize(), SeverityID.Unknown
SeverityID,
finding.metadata.Severity.capitalize(),
SeverityID.Unknown,
)
finding_status = self.get_finding_status_id(finding.muted)
@@ -66,27 +69,35 @@ class OCSF(Output):
activity_name=finding_activity.name,
finding_info=FindingInformation(
created_time_dt=finding.timestamp,
created_time=int(finding.timestamp.timestamp()),
desc=finding.description,
title=finding.check_title,
uid=finding.finding_uid,
created_time=(
int(finding.timestamp.timestamp())
if isinstance(finding.timestamp, datetime)
else finding.timestamp
),
desc=finding.metadata.Description,
title=finding.metadata.CheckTitle,
uid=finding.uid,
name=finding.resource_name,
product_uid="prowler",
types=[finding.check_type],
types=finding.metadata.CheckType,
),
time_dt=finding.timestamp,
time=int(finding.timestamp.timestamp()),
time=(
int(finding.timestamp.timestamp())
if isinstance(finding.timestamp, datetime)
else finding.timestamp
),
remediation=Remediation(
desc=finding.remediation_recommendation_text,
desc=finding.metadata.Remediation.Recommendation.Text,
references=list(
filter(
None,
[
finding.remediation_code_nativeiac,
finding.remediation_code_terraform,
finding.remediation_code_cli,
finding.remediation_code_other,
finding.remediation_recommendation_url,
finding.metadata.Remediation.Code.NativeIaC,
finding.metadata.Remediation.Code.Terraform,
finding.metadata.Remediation.Code.CLI,
finding.metadata.Remediation.Code.Other,
finding.metadata.Remediation.Recommendation.Url,
],
)
),
@@ -97,36 +108,36 @@ class OCSF(Output):
status=finding_status.name,
status_code=finding.status,
status_detail=finding.status_extended,
risk_details=finding.risk,
risk_details=finding.metadata.Risk,
resources=(
[
ResourceDetails(
labels=unroll_dict_to_list(finding.resource_tags),
name=finding.resource_name,
uid=finding.resource_uid,
group=Group(name=finding.service_name),
type=finding.resource_type,
group=Group(name=finding.metadata.ServiceName),
type=finding.metadata.ResourceType,
# TODO: this should be included only if using the Cloud profile
cloud_partition=finding.partition,
region=finding.region,
data={"details": finding.resource_details},
)
]
if finding.provider != "kubernetes"
if finding.metadata.Provider != "kubernetes"
else [
ResourceDetails(
labels=unroll_dict_to_list(finding.resource_tags),
name=finding.resource_name,
uid=finding.resource_uid,
group=Group(name=finding.service_name),
type=finding.resource_type,
group=Group(name=finding.metadata.ServiceName),
type=finding.metadata.ResourceType,
data={"details": finding.resource_details},
namespace=finding.region.replace("namespace: ", ""),
)
]
),
metadata=Metadata(
event_code=finding.check_id,
event_code=finding.metadata.CheckID,
product=Product(
uid="prowler",
name="Prowler",
@@ -135,7 +146,7 @@ class OCSF(Output):
),
profiles=(
["cloud", "datetime"]
if finding.provider != "kubernetes"
if finding.metadata.Provider != "kubernetes"
else ["container", "datetime"]
),
tenant_uid=finding.account_organization_uid,
@@ -143,11 +154,11 @@ class OCSF(Output):
type_uid=DetectionFindingTypeID.Create,
type_name=f"Detection Finding: {DetectionFindingTypeID.Create.name}",
unmapped={
"related_url": finding.related_url,
"categories": finding.categories,
"depends_on": finding.depends_on,
"related_to": finding.related_to,
"notes": finding.notes,
"related_url": finding.metadata.RelatedUrl,
"categories": finding.metadata.Categories,
"depends_on": finding.metadata.DependsOn,
"related_to": finding.metadata.RelatedTo,
"notes": finding.metadata.Notes,
"compliance": finding.compliance,
},
)
@@ -0,0 +1,61 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 8000 to 8999 are reserved for Slack exceptions
class SlackBaseException(ProwlerException):
"""Base class for Slack errors."""
SLACK_ERROR_CODES = {
(8000, "SlackClientError"): {
"message": "Slack ClientError occurred",
"remediation": "Check your Slack client configuration and permissions.",
},
(8001, "SlackNoCredentialsError"): {
"message": "Invalid Slack credentials found",
"remediation": "Some aspect of authentication cannot be validated. Either the provided token is invalid or the request originates from an IP address disallowed from making the request.",
},
(8002, "SlackChannelNotFound"): {
"message": "Slack channel not found",
"remediation": "Check the channel name and ensure it exists.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
error_info = self.SLACK_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code,
source="Slack",
file=file,
original_exception=original_exception,
error_info=error_info,
)
class SlackCredentialsError(SlackBaseException):
"""Base class for Slack credentials errors."""
def __init__(self, code, file=None, original_exception=None, message=None):
super().__init__(code, file, original_exception, message)
class SlackClientError(SlackCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
8000, file=file, original_exception=original_exception, message=message
)
class SlackNoCredentialsError(SlackCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
8001, file=file, original_exception=original_exception, message=message
)
class SlackChannelNotFound(SlackCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
8002, file=file, original_exception=original_exception, message=message
)
+72 -2
View File
@@ -1,3 +1,4 @@
import os
from typing import Any
from slack_sdk import WebClient
@@ -5,6 +6,12 @@ from slack_sdk.web.base_client import SlackResponse
from prowler.config.config import aws_logo, azure_logo, gcp_logo, square_logo_img
from prowler.lib.logger import logger
from prowler.lib.outputs.slack.exceptions.exceptions import (
SlackChannelNotFound,
SlackClientError,
SlackNoCredentialsError,
)
from prowler.providers.common.models import Connection
class Slack:
@@ -43,6 +50,7 @@ class Slack:
username="Prowler",
icon_url=square_logo_img,
channel=f"#{self.channel}",
text="Prowler Scan Summary",
blocks=self.__create_message_blocks__(identity, logo, stats, args),
)
return response
@@ -50,7 +58,6 @@ class Slack:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return error
def __create_message_identity__(self, provider: Any):
"""
@@ -178,7 +185,7 @@ class Slack:
"accessory": {
"type": "button",
"text": {"type": "plain_text", "text": "Prowler :slack:"},
"url": "https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog",
"url": "https://goto.prowler.com/slack",
},
},
{
@@ -230,3 +237,66 @@ class Slack:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@staticmethod
def test_connection(
token: str,
channel: str,
raise_on_exception: bool = True,
) -> Connection:
"""
Test the Slack connection by validating the provided token and channel.
Args:
token (str): The Slack token to be tested.
channel (str): The Slack channel to be validated.
Returns:
Connection: A Connection object.
"""
try:
client = WebClient(token=token)
# Test if the token is valid
auth_response = client.auth_test()
if auth_response["ok"]:
# Test if the channel is accessible
channels_response = client.conversations_info(
token=token, channel=channel
)
if channels_response["ok"]:
return Connection(is_connected=True)
else:
exception = SlackChannelNotFound(
file=os.path.basename(__file__),
message=(
channels_response["error"]
if "error" in channels_response
else "Unknown error"
),
)
if raise_on_exception:
raise exception
return Connection(error=exception)
else:
exception = SlackNoCredentialsError(
file=os.path.basename(__file__),
message=(
auth_response["error"]
if "error" in auth_response
else "Unknown error"
),
)
if raise_on_exception:
raise exception
return Connection(error=exception)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
if raise_on_exception:
raise SlackClientError(
file=os.path.basename(__file__),
original_exception=error,
) from error
return Connection(error=error)
+88
View File
@@ -0,0 +1,88 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 5000 to 5999 are reserved for Scan exceptions
class ScanBaseException(ProwlerException):
"""Base class for Scan errors."""
SCAN_ERROR_CODES = {
(5000, "ScanInvalidSeverityError"): {
"message": "Invalid severity level provided.",
"remediation": "Please provide a valid severity level. Valid severities are: critical, high, medium, low, informational.",
},
(5001, "ScanInvalidCheckError"): {
"message": "Invalid check provided.",
"remediation": "Please provide a valid check name.",
},
(5002, "ScanInvalidServiceError"): {
"message": "Invalid service provided.",
"remediation": "Please provide a valid service name.",
},
(5003, "ScanInvalidComplianceFrameworkError"): {
"message": "Invalid compliance framework provided.",
"remediation": "Please provide a valid compliance framework name for the chosen provider.",
},
(5004, "ScanInvalidCategoryError"): {
"message": "Invalid category provided.",
"remediation": "Please provide a valid category name.",
},
(5005, "ScanInvalidStatusError"): {
"message": "Invalid status provided.",
"remediation": "Please provide a valid status: FAIL, PASS, MANUAL.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
module = "Scan"
error_info = self.SCAN_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code=code,
source=module,
file=file,
original_exception=original_exception,
error_info=error_info,
)
class ScanInvalidSeverityError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5000, file=file, original_exception=original_exception, message=message
)
class ScanInvalidCheckError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5001, file=file, original_exception=original_exception, message=message
)
class ScanInvalidServiceError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5002, file=file, original_exception=original_exception, message=message
)
class ScanInvalidComplianceFrameworkError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5003, file=file, original_exception=original_exception, message=message
)
class ScanInvalidCategoryError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5004, file=file, original_exception=original_exception, message=message
)
class ScanInvalidStatusError(ScanBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
5005, file=file, original_exception=original_exception, message=message
)
+173 -9
View File
@@ -1,8 +1,27 @@
import datetime
from typing import Generator
from prowler.lib.check.check import execute, import_check, update_audit_metadata
from prowler.lib.check.check import (
execute,
import_check,
list_services,
update_audit_metadata,
)
from prowler.lib.check.checks_loader import load_checks_to_execute
from prowler.lib.check.compliance import update_checks_metadata_with_compliance
from prowler.lib.check.compliance_models import Compliance
from prowler.lib.check.models import CheckMetadata, Severity
from prowler.lib.logger import logger
from prowler.lib.outputs.common import Status
from prowler.lib.outputs.finding import Finding
from prowler.lib.scan.exceptions.exceptions import (
ScanInvalidCategoryError,
ScanInvalidCheckError,
ScanInvalidComplianceFrameworkError,
ScanInvalidServiceError,
ScanInvalidSeverityError,
ScanInvalidStatusError,
)
from prowler.providers.common.models import Audit_Metadata
from prowler.providers.common.provider import Provider
@@ -18,29 +37,161 @@ class Scan:
_service_checks_completed: dict[str, set[str]]
_progress: float = 0.0
_findings: list = []
_duration: int = 0
_status: list[str] = None
def __init__(self, provider: Provider, checks_to_execute: list[str]):
def __init__(
self,
provider: Provider,
checks: list[str] = None,
services: list[str] = None,
compliances: list[str] = None,
categories: list[str] = None,
severities: list[str] = None,
excluded_checks: list[str] = None,
excluded_services: list[str] = None,
status: list[str] = None,
):
"""
Scan is the class that executes the checks and yields the progress and the findings.
Params:
provider: Provider -> The provider to scan
checks_to_execute: list[str] -> The checks to execute
checks: list[str] -> The checks to execute
services: list[str] -> The services to scan
compliances: list[str] -> The compliances to check
categories: list[str] -> The categories of the checks
severities: list[str] -> The severities of the checks
excluded_checks: list[str] -> The checks to exclude
excluded_services: list[str] -> The services to exclude
status: list[str] -> The status of the checks
Raises:
ScanInvalidCheckError: If the check does not exist in the provider or is from another provider.
ScanInvalidServiceError: If the service does not exist in the provider.
ScanInvalidComplianceFrameworkError: If the compliance framework does not exist in the provider.
ScanInvalidCategoryError: If the category does not exist in the provider.
ScanInvalidSeverityError: If the severity does not exist in the provider.
ScanInvalidStatusError: If the status does not exist in the provider.
"""
self._provider = provider
# Remove duplicated checks and sort them
self._checks_to_execute = sorted(list(set(checks_to_execute)))
self._number_of_checks_to_execute = len(checks_to_execute)
# Validate the status
if status:
try:
for s in status:
Status(s)
if not self._status:
self._status = []
if s not in self._status:
self._status.append(s)
except ValueError:
raise ScanInvalidStatusError(f"Invalid status provided: {s}.")
service_checks_to_execute = get_service_checks_to_execute(checks_to_execute)
# Load bulk compliance frameworks
bulk_compliance_frameworks = Compliance.get_bulk(provider.type)
# Get bulk checks metadata for the provider
bulk_checks_metadata = CheckMetadata.get_bulk(provider.type)
# Complete checks metadata with the compliance framework specification
bulk_checks_metadata = update_checks_metadata_with_compliance(
bulk_compliance_frameworks, bulk_checks_metadata
)
# Create a list of valid categories
valid_categories = set()
for check, metadata in bulk_checks_metadata.items():
for category in metadata.Categories:
if category not in valid_categories:
valid_categories.add(category)
# Validate checks
if checks:
for check in checks:
if check not in bulk_checks_metadata.keys():
raise ScanInvalidCheckError(f"Invalid check provided: {check}.")
# Validate services
if services:
for service in services:
if service not in list_services(provider.type):
raise ScanInvalidServiceError(
f"Invalid service provided: {service}."
)
# Validate compliances
if compliances:
for compliance in compliances:
if compliance not in bulk_compliance_frameworks.keys():
raise ScanInvalidComplianceFrameworkError(
f"Invalid compliance provided: {compliance}."
)
# Validate categories
if categories:
for category in categories:
if category not in valid_categories:
raise ScanInvalidCategoryError(
f"Invalid category provided: {category}."
)
# Validate severity
if severities:
for severity in severities:
try:
Severity(severity)
except ValueError:
raise ScanInvalidSeverityError(
f"Invalid severity provided: {severity}."
)
# Load checks to execute
self._checks_to_execute = sorted(
load_checks_to_execute(
bulk_checks_metadata=bulk_checks_metadata,
bulk_compliance_frameworks=bulk_compliance_frameworks,
check_list=checks,
service_list=services,
compliance_frameworks=compliances,
categories=categories,
severities=severities,
provider=provider.type,
checks_file=None,
)
)
# Exclude checks
if excluded_checks:
for check in excluded_checks:
if check in self._checks_to_execute:
self._checks_to_execute.remove(check)
else:
raise ScanInvalidCheckError(
f"Invalid check provided: {check}. Check does not exist in the provider."
)
# Exclude services
if excluded_services:
for check in self._checks_to_execute:
if get_service_name_from_check_name(check) in excluded_services:
self._checks_to_execute.remove(check)
else:
raise ScanInvalidServiceError(
f"Invalid service provided: {check}. Service does not exist in the provider."
)
self._number_of_checks_to_execute = len(self._checks_to_execute)
service_checks_to_execute = get_service_checks_to_execute(
self._checks_to_execute
)
service_checks_completed = dict()
self._service_checks_to_execute = service_checks_to_execute
self._service_checks_completed = service_checks_completed
@property
def checks_to_execute(self) -> set[str]:
def checks_to_execute(self) -> list[str]:
return self._checks_to_execute
@property
@@ -61,6 +212,10 @@ class Scan:
self._number_of_checks_completed / self._number_of_checks_to_execute * 100
)
@property
def duration(self) -> int:
return self._duration
@property
def findings(self) -> list:
return self._findings
@@ -95,6 +250,8 @@ class Scan:
audit_progress=0,
)
start_time = datetime.datetime.now()
for check_name in checks_to_execute:
try:
# Recover service from check name
@@ -119,6 +276,12 @@ class Scan:
output_options=None,
)
# Filter the findings by the status
if self._status:
for finding in check_findings:
if finding.status not in self._status:
check_findings.remove(finding)
# Store findings
self._findings.extend(check_findings)
@@ -149,7 +312,6 @@ class Scan:
]
yield self.progress, findings
# If check does not exists in the provider or is from another provider
except ModuleNotFoundError:
logger.error(
@@ -159,6 +321,8 @@ class Scan:
logger.error(
f"{check_name} - {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
# Update the scan duration when all checks are completed
self._duration = int((datetime.datetime.now() - start_time).total_seconds())
except Exception as error:
logger.error(
f"{check_name} - {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
+45 -3
View File
@@ -1,5 +1,6 @@
import json
import os
from operator import attrgetter
try:
import grp
@@ -16,7 +17,7 @@ from io import TextIOWrapper
from ipaddress import ip_address
from os.path import exists
from time import mktime
from typing import Optional
from typing import Any, Optional
from colorama import Style
from detect_secrets import SecretsCollection
@@ -120,7 +121,7 @@ def detect_secrets_scan(
{"name": "HexHighEntropyString", "limit": 3.0},
{"name": "IbmCloudIamDetector"},
{"name": "IbmCosHmacDetector"},
{"name": "IPPublicDetector"},
# {"name": "IPPublicDetector"}, https://github.com/Yelp/detect-secrets/pull/885
{"name": "JwtTokenDetector"},
{"name": "KeywordDetector"},
{"name": "MailchimpDetector"},
@@ -133,7 +134,7 @@ def detect_secrets_scan(
{"name": "SoftlayerDetector"},
{"name": "SquareOAuthDetector"},
{"name": "StripeDetector"},
{"name": "TelegramBotTokenDetector"},
# {"name": "TelegramBotTokenDetector"}, https://github.com/Yelp/detect-secrets/pull/878
{"name": "TwilioKeyDetector"},
],
"filters_used": [
@@ -272,3 +273,44 @@ def print_boxes(messages: list, report_title: str):
f"{Style.BRIGHT}{Style.RESET_ALL} · {message}{Style.BRIGHT}{Style.RESET_ALL}"
)
print()
def dict_to_lowercase(d):
"""
Convert all keys in a dictionary to lowercase.
This function takes a dictionary and returns a new dictionary
with all the keys converted to lowercase. If a value in the
dictionary is another dictionary, the function will recursively
convert the keys of that dictionary to lowercase as well.
Args:
d (dict): The dictionary to convert.
Returns:
dict: A new dictionary with all keys in lowercase.
"""
new_dict = {}
for k, v in d.items():
if isinstance(v, dict):
v = dict_to_lowercase(v)
new_dict[k.lower()] = v
return new_dict
def get_nested_attribute(obj: Any, attr: str) -> Any:
"""
Get a nested attribute from an object.
Args:
obj (Any): The object to get the attribute from.
attr (str): The attribute to get.
Returns:
Any: The attribute value if present, otherwise "".
"""
try:
return attrgetter(attr)(obj)
except AttributeError:
return ""
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return ""
+474 -109
View File
@@ -2,8 +2,8 @@ import os
import pathlib
from datetime import datetime
from re import fullmatch
from typing import Optional
from boto3 import client
from boto3.session import Session
from botocore.config import Config
from botocore.credentials import RefreshableCredentials
@@ -13,7 +13,12 @@ from colorama import Fore, Style
from pytz import utc
from tzlocal import get_localzone
from prowler.config.config import aws_services_json_file, get_default_mute_file_path
from prowler.config.config import (
aws_services_json_file,
default_config_file_path,
get_default_mute_file_path,
load_and_validate_config_file,
)
from prowler.lib.check.utils import list_modules, recover_checks_from_service
from prowler.lib.logger import logger
from prowler.lib.utils.utils import open_file, parse_json_file, print_boxes
@@ -24,17 +29,22 @@ from prowler.providers.aws.config import (
ROLE_SESSION_NAME,
)
from prowler.providers.aws.exceptions.exceptions import (
AWSAccessKeyIDInvalidError,
AWSArgumentTypeValidationError,
AWSAssumeRoleError,
AWSClientError,
AWSIAMRoleARNEmptyResource,
AWSIAMRoleARNInvalidAccountID,
AWSIAMRoleARNInvalidResourceType,
AWSIAMRoleARNPartitionEmpty,
AWSIAMRoleARNRegionNotEmtpy,
AWSIAMRoleARNServiceNotIAMnorSTS,
AWSIAMRoleARNEmptyResourceError,
AWSIAMRoleARNInvalidAccountIDError,
AWSIAMRoleARNInvalidResourceTypeError,
AWSIAMRoleARNPartitionEmptyError,
AWSIAMRoleARNRegionNotEmtpyError,
AWSIAMRoleARNServiceNotIAMnorSTSError,
AWSInvalidPartitionError,
AWSInvalidProviderIdError,
AWSNoCredentialsError,
AWSProfileNotFoundError,
AWSSecretAccessKeyInvalidError,
AWSSessionTokenExpiredError,
AWSSetUpSessionError,
)
from prowler.providers.aws.lib.arn.arn import parse_iam_credentials_arn
@@ -53,12 +63,32 @@ from prowler.providers.aws.models import (
AWSMFAInfo,
AWSOrganizationsInfo,
AWSSession,
Partition,
)
from prowler.providers.common.models import Audit_Metadata, Connection
from prowler.providers.common.provider import Provider
class AwsProvider(Provider):
"""
AwsProvider class is the main class for the AWS provider.
This class is responsible for initializing the AWS provider, setting up the AWS session, validating the AWS
credentials, assuming an IAM role, getting the AWS Organizations metadata, and setting the AWS identity.
Attributes:
_type (str): The provider type.
_identity (AWSIdentityInfo): The AWS provider identity information.
_session (AWSSession): The AWS provider session.
_organizations_metadata (AWSOrganizationsInfo): The AWS Organizations metadata.
_audit_resources (list): The list of resources to audit.
_audit_config (dict): The audit configuration.
_scan_unused_services (bool): A boolean indicating whether to scan unused services.
_enabled_regions (set): The set of enabled regions.
_mutelist (AWSMutelist): The AWS provider mutelist.
audit_metadata (Audit_Metadata): The audit metadata.
"""
_type: str = "aws"
_identity: AWSIdentityInfo
_session: AWSSession
@@ -67,6 +97,7 @@ class AwsProvider(Provider):
_audit_config: dict
_scan_unused_services: bool = False
_enabled_regions: set = set()
_mutelist: AWSMutelist
# TODO: this is not optional, enforce for all providers
audit_metadata: Audit_Metadata
@@ -81,30 +112,42 @@ class AwsProvider(Provider):
profile: str = None,
regions: set = set(),
organizations_role_arn: str = None,
scan_unused_services: bool = None,
scan_unused_services: bool = False,
resource_tags: list[str] = [],
resource_arn: list[str] = [],
audit_config: dict = {},
config_path: str = None,
config_content: dict = None,
fixer_config: dict = {},
mutelist_path: str = None,
mutelist_content: dict = None,
aws_access_key_id: str = None,
aws_secret_access_key: str = None,
aws_session_token: Optional[str] = None,
):
"""
Initializes the AWS provider.
Arguments:
Args:
- retries_max_attempts: The maximum number of retries for the AWS client.
- role_arn: The ARN of the IAM role to assume.
- session_duration: The duration of the session in seconds.
- session_duration: The duration of the session in seconds, between 900 and 43200.
- external_id: The external ID to use when assuming the IAM role.
- role_session_name: The name of the session when assuming the IAM role.
- mfa: A boolean indicating whether MFA is enabled.
- profile: The name of the AWS CLI profile to use.
- regions: A set of regions to audit.
- organizations_role_arn: The ARN of the AWS Organizations IAM role to assume.
- scan_unused_services: A boolean indicating whether to scan unused services.
- scan_unused_services: A boolean indicating whether to scan unused services. False by default.
- resource_tags: A list of tags to filter the resources to audit.
- resource_arn: A list of ARNs of the resources to audit.
- audit_config: The audit configuration.
- config_path: The path to the configuration file.
- config_content: The content of the configuration file.
- fixer_config: The fixer configuration.
- mutelist_path: The path to the mutelist file.
- mutelist_content: The content of the mutelist file.
- aws_access_key_id: The AWS access key ID.
- aws_secret_access_key: The AWS secret access key.
- aws_session_token: The AWS session token, optional.
Raises:
- ArgumentTypeError: If the input MFA ARN is invalid.
@@ -112,14 +155,52 @@ class AwsProvider(Provider):
- ArgumentTypeError: If the input external ID is invalid.
- ArgumentTypeError: If the input role session name is invalid.
Usage:
- Boto3 is used so we follow their credential setup process:
- Authentication: Make sure you have properly configured your AWS CLI with a valid Access Key and Region or declare the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.
- aws configure
or
- export AWS_ACCESS_KEY_ID="ASXXXXXXX"
export AWS_SECRET_ACCESS_KEY="XXXXXXXXX"
export AWS_SESSION_TOKEN="XXXXXXXXX"
- To create a new aws object you can use:
- aws = AwsProvider()
- aws = AwsProvider(aws_access_key_id="ASXXXXXXX", aws_secret_access_key="XXXXXXXXX", aws_session_token="XXXXXXXXX")
- Profile: If you have multiple profiles in your AWS CLI configuration, you can specify the profile to use:
- aws = AwsProvider(profile="profile_name")
- MFA: If you have MFA enabled you can specify it:
- aws = AwsProvider(mfa=True)
* Note: If you have MFA enabled you will be prompted to enter the MFA ARN and the MFA TOTP code.
* Note: Take into account that you can use static credentials or a profile, with the combination of MFA.
- Assume Role: *Requires authentication.* Prowler can be used against multiple accounts using IAM Assume Role features depending on each use case:
- Set up a custom profile inside your AWS CLI configuration file:
- [profile profile_name]
role_arn = arn:aws:iam::123456789012:role/role_name
- aws = AwsProvider(profile="profile_name")
- Use role_arn directly:
- aws = AwsProvider(role_arn="arn:aws:iam::123456789012:role/role_name")
- Use role_arn with session duration(in seconds, by default 3600) and external ID:
- aws = AwsProvider(role_arn="arn:aws:iam::123456789012:role/role_name", session_duration=3600, external_id="external_id")
- Use custom role session name:
- aws = AwsProvider(role_arn="arn:aws:iam::123456789012:role/role_name", role_session_name="custom_session_name")
* Note: You can use the combination of MFA with Assume Role.
- aws = AwsProvider(role_arn="arn:aws:iam::123456789012:role/role_name", mfa=True)
"""
logger.info("Initializing AWS provider ...")
######## AWS Session
logger.info("Generating original session ...")
# Configure the initial AWS Session using the local credentials: profile or environment variables
aws_session = self.setup_session(mfa, profile)
aws_session = self.setup_session(
mfa=mfa,
profile=profile,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
aws_session_token=aws_session_token,
)
session_config = self.set_session_config(retries_max_attempts)
# Current session and the original session points to the same session object until we get a new one, if needed
self._session = AWSSession(
@@ -264,10 +345,32 @@ class AwsProvider(Provider):
self._scan_unused_services = scan_unused_services
# Audit Config
self._audit_config = audit_config
if config_content:
self._audit_config = config_content
else:
if not config_path:
config_path = default_config_file_path
self._audit_config = load_and_validate_config_file(self._type, config_path)
# Fixer Config
self._fixer_config = fixer_config
# Mutelist
if mutelist_content:
self._mutelist = AWSMutelist(
mutelist_content=mutelist_content,
session=self._session.current_session,
aws_account_id=self._identity.account,
)
else:
if not mutelist_path:
mutelist_path = get_default_mute_file_path(self.type)
self._mutelist = AWSMutelist(
mutelist_path=mutelist_path,
session=self._session.current_session,
aws_account_id=self._identity.account,
)
Provider.set_global_provider(self)
@property
@@ -309,37 +412,6 @@ class AwsProvider(Provider):
"""
return self._mutelist
# TODO: this is going to be called from another place soon, since the provider
# shouldn't hold the mutelist
@mutelist.setter
def mutelist(self, mutelist_path):
"""
mutelist.setter sets the provider's mutelist.
"""
# Set default mutelist path if none is set
if not mutelist_path:
mutelist_path = get_default_mute_file_path(self.type)
self._mutelist = AWSMutelist(
mutelist_path=mutelist_path,
session=self._session.current_session,
aws_account_id=self._identity.account,
)
@property
def get_output_mapping(self):
return {
"auth_method": "identity.profile",
"provider": "type",
"account_uid": "identity.account",
"account_name": "organizations_metadata.account_name",
"account_email": "organizations_metadata.account_email",
"account_organization_uid": "organizations_metadata.organization_arn",
"account_organization_name": "organizations_metadata.organization_id",
"account_tags": "organizations_metadata.account_tags",
"partition": "identity.partition",
}
# TODO: This can be moved to another class since it doesn't need self
def get_organizations_info(
self, organizations_session: Session, aws_account_id: str
@@ -347,7 +419,7 @@ class AwsProvider(Provider):
"""
get_organizations_info returns a AWSOrganizationsInfo object if the account to be audited is a delegated administrator for AWS Organizations or if the AWS Organizations Role ARN (--organizations-role) is passed.
Arguments:
Args:
- organizations_session: needs to be a Session object with permissions to do organizations:DescribeAccount and organizations:ListTagsForResource.
- aws_account_id: is the AWS Account ID from which we want to get the AWS Organizations account metadata
@@ -404,6 +476,21 @@ class AwsProvider(Provider):
regions: set,
profile_region: str,
) -> AWSIdentityInfo:
"""
set_identity sets the AWS provider identity information.
Args:
- caller_identity: The AWS caller identity information.
- profile: The AWS CLI profile name.
- regions: A set of regions to audit.
- profile_region: The AWS CLI profile region.
Returns:
- AWSIdentityInfo: The AWS provider identity information.
Raises:
- AWSInvalidProviderIdError: If the AWS provider ID is invalid.
"""
logger.info(f"Original AWS Caller Identity UserId: {caller_identity.user_id}")
logger.info(f"Original AWS Caller Identity ARN: {caller_identity.arn}")
@@ -423,17 +510,49 @@ class AwsProvider(Provider):
def setup_session(
mfa: bool = False,
profile: str = None,
aws_access_key_id: str = None,
aws_secret_access_key: str = None,
aws_session_token: Optional[str] = None,
) -> Session:
"""
setup_session sets up an AWS session using the provided credentials.
Args:
- mfa: A boolean indicating whether MFA is enabled.
- profile: The name of the AWS CLI profile to use.
- aws_access_key_id: The AWS access key ID.
- aws_secret_access_key: The AWS secret access key.
- aws_session_token: The AWS session token, optional.
Returns:
- Session: The AWS session.
Raises:
- AWSSetUpSessionError: If an error occurs during the setup process.
"""
try:
logger.info("Creating original session ...")
logger.debug("Creating original session ...")
session_arguments = {}
if profile:
session_arguments["profile_name"] = profile
elif aws_access_key_id and aws_secret_access_key:
session_arguments["aws_access_key_id"] = aws_access_key_id
session_arguments["aws_secret_access_key"] = aws_secret_access_key
if aws_session_token:
session_arguments["aws_session_token"] = aws_session_token
if mfa:
session = Session(**session_arguments)
sts_client = session.client("sts")
# TODO: pass values from the input
mfa_info = AwsProvider.input_role_mfa_token_and_code()
# TODO: validate MFA ARN here
get_session_token_arguments = {
"SerialNumber": mfa_info.arn,
"TokenCode": mfa_info.totp,
}
sts_client = client("sts")
session_credentials = sts_client.get_session_token(
**get_session_token_arguments
)
@@ -445,12 +564,9 @@ class AwsProvider(Provider):
aws_session_token=session_credentials["Credentials"][
"SessionToken"
],
profile_name=profile,
)
else:
return Session(
profile_name=profile,
)
return Session(**session_arguments)
except Exception as error:
logger.critical(
f"AWSSetUpSessionError[{error.__traceback__.tb_lineno}]: {error}"
@@ -555,6 +671,21 @@ class AwsProvider(Provider):
return refreshed_credentials
def print_credentials(self):
"""
Print the AWS credentials.
This method prints the AWS credentials used by the provider.
Example output:
```
Using the AWS credentials below:
AWS-CLI Profile: default
AWS Regions: all
AWS Account: 123456789012
User Id: AIDAJDPLRKLG7EXAMPLE
Caller Identity ARN: arn:aws:iam::123456789012:user/prowler
```
"""
# Beautify audited regions, set "all" if there is no filter region
regions = (
", ".join(self._identity.audited_regions)
@@ -596,7 +727,9 @@ class AwsProvider(Provider):
"""
try:
regional_clients = {}
service_regions = self.get_available_aws_service_regions(service)
service_regions = AwsProvider.get_available_aws_service_regions(
service, self._identity.partition, self._identity.audited_regions
)
# Get the regions enabled for the account and get the intersection with the service available regions
if self._enabled_regions:
@@ -617,14 +750,26 @@ class AwsProvider(Provider):
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def get_available_aws_service_regions(self, service: str) -> set:
@staticmethod
def get_available_aws_service_regions(
service: str, partition: str = "aws", audited_regions: set = None
) -> set:
"""
get_available_aws_service_regions returns the available regions for the given service and partition.
Args:
- service: The AWS service name.
- partition: The AWS partition name. Default is "aws".
- audited_regions: A set of regions to audit. Default is None.
Returns:
- A set of strings representing the available regions for the given service and partition.
"""
data = read_aws_regions_file()
json_regions = set(
data["services"][service]["regions"][self._identity.partition]
)
if self._identity.audited_regions:
json_regions = set(data["services"][service]["regions"][partition])
if audited_regions:
# Get common regions between input and json
regions = json_regions.intersection(self._identity.audited_regions)
regions = json_regions.intersection(audited_regions)
else: # Get all regions from json of the service and partition
regions = json_regions
return regions
@@ -632,13 +777,26 @@ class AwsProvider(Provider):
def get_checks_from_input_arn(self) -> set:
"""
get_checks_from_input_arn gets the list of checks from the input arns
Returns:
- set: set of strings representing the checks from the input arns
Example:
checks = get_checks_from_input_arn()
"""
checks_from_arn = set()
is_subservice_in_checks = False
# Handle if there are audit resources so only their services are executed
if self._audit_resources:
# TODO: this should be retrieved automatically
services_without_subservices = ["guardduty", "kms", "s3", "elb", "efs"]
services_without_subservices = [
"guardduty",
"kms",
"s3",
"elb",
"efs",
"sqs",
]
service_list = set()
sub_service_list = set()
for resource in self._audit_resources:
@@ -698,7 +856,18 @@ class AwsProvider(Provider):
# TODO: This can be moved to another class since it doesn't need self
def get_regions_from_audit_resources(self, audit_resources: list) -> set:
"""get_regions_from_audit_resources gets the regions from the audit resources arns"""
"""get_regions_from_audit_resources gets the regions from the audit resources arns
Args:
- audit_resources: list of ARNs of the resources to audit
Returns:
- set: set of strings representing the regions from the audit resources arns
Example:
audit_resources = ["arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0"]
regions = get_regions_from_audit_resources(audit_resources)
"""
audited_regions = set()
for resource in audit_resources:
region = resource.split(":")[3]
@@ -758,9 +927,22 @@ class AwsProvider(Provider):
raise error
def get_default_region(self, service: str) -> str:
"""get_default_region returns the default region based on the profile and audited service regions"""
"""get_default_region returns the default region based on the profile and audited service regions
Args:
- service: The AWS service name
Returns:
- str: The default region for the given service
Example:
service = "ec2"
default_region = get_default_region(service)
"""
try:
service_regions = self.get_available_aws_service_regions(service)
service_regions = AwsProvider.get_available_aws_service_regions(
service, self._identity.partition, self._identity.audited_regions
)
default_region = self.get_global_region()
# global region of the partition when all regions are audited and there is no profile region
if self._identity.profile_region in service_regions:
@@ -777,7 +959,14 @@ class AwsProvider(Provider):
raise error
def get_global_region(self) -> str:
"""get_global_region returns the global region based on the audited partition"""
"""get_global_region returns the global region based on the audited partition
Returns:
- str: The global region for the audited partition
Example:
global_region = get_global_region()a
"""
global_region = "us-east-1"
if self._identity.partition == "aws-cn":
global_region = "cn-north-1"
@@ -789,7 +978,14 @@ class AwsProvider(Provider):
@staticmethod
def input_role_mfa_token_and_code() -> AWSMFAInfo:
"""input_role_mfa_token_and_code ask for the AWS MFA ARN and TOTP and returns it."""
"""input_role_mfa_token_and_code ask for the AWS MFA ARN and TOTP and returns it.
Returns:
- AWSMFAInfo: An object containing the MFA ARN and TOTP code
Example:
mfa_info = input_role_mfa_token_and_code()
"""
mfa_ARN = input("Enter ARN of MFA: ")
mfa_TOTP = input("Enter MFA code: ")
return AWSMFAInfo(arn=mfa_ARN, totp=mfa_TOTP)
@@ -797,6 +993,12 @@ class AwsProvider(Provider):
def set_session_config(self, retries_max_attempts: int) -> Config:
"""
set_session_config returns a botocore Config object with the Prowler user agent and the default retrier configuration if nothing is passed as argument
Args:
- retries_max_attempts: The maximum number of retries for the standard retrier config
Returns:
- Config: The botocore Config object
"""
# Set the maximum retries for the standard retrier config
default_session_config = Config(
@@ -823,6 +1025,13 @@ class AwsProvider(Provider):
) -> AWSCredentials:
"""
assume_role assumes the IAM roles passed with the given session and returns AWSCredentials
Args:
- session: The AWS session object
- assumed_role_info: The AWSAssumeRoleInfo object
Returns:
- AWSCredentials: The AWS credentials for the assumed role
"""
try:
role_session_name = (
@@ -874,7 +1083,14 @@ class AwsProvider(Provider):
)
def get_aws_enabled_regions(self, current_session: Session) -> set:
"""get_aws_enabled_regions returns a set of enabled AWS regions"""
"""get_aws_enabled_regions returns a set of enabled AWS regions
Args:
- current_session: The AWS session object
Returns:
- set: set of strings representing the enabled AWS regions
"""
try:
# EC2 Client to check enabled regions
service = "ec2"
@@ -898,6 +1114,12 @@ class AwsProvider(Provider):
# TODO: review this function
# Maybe this should be done within the AwsProvider and not in __main__.py
def get_checks_to_execute_by_audit_resources(self) -> set[str]:
"""
get_checks_to_execute_by_audit_resources gets the checks to execute based on the audit resources
Returns:
- set: set of strings representing the checks to execute
"""
# Once the provider is set and we have the eventual checks from arn, it is time to exclude the others
try:
checks = set()
@@ -939,6 +1161,31 @@ class AwsProvider(Provider):
arn=ARN(caller_identity.get("Arn")),
region=aws_region,
)
except ClientError as client_error:
logger.error(
f"{client_error.__class__.__name__}[{client_error.__traceback__.tb_lineno}]: {client_error}"
)
if client_error.response["Error"]["Code"] == "InvalidClientTokenId":
raise AWSAccessKeyIDInvalidError(
original_exception=client_error,
file=pathlib.Path(__file__).name,
)
elif client_error.response["Error"]["Code"] == "SignatureDoesNotMatch":
raise AWSSecretAccessKeyInvalidError(
original_exception=client_error,
file=pathlib.Path(__file__).name,
)
elif client_error.response["Error"]["Code"] == "ExpiredToken":
raise AWSSessionTokenExpiredError(
original_exception=client_error,
file=pathlib.Path(__file__).name,
)
else:
raise AWSClientError(
original_exception=client_error,
file=pathlib.Path(__file__).name,
)
except Exception as error:
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
@@ -955,6 +1202,10 @@ class AwsProvider(Provider):
external_id: str = None,
mfa_enabled: bool = False,
raise_on_exception: bool = True,
aws_access_key_id: str = None,
aws_secret_access_key: str = None,
aws_session_token: Optional[str] = None,
provider_id: Optional[str] = None,
) -> Connection:
"""
Test the connection to AWS with one of the Boto3 credentials methods.
@@ -968,6 +1219,10 @@ class AwsProvider(Provider):
external_id (str): The external ID to use when assuming the role.
mfa_enabled (bool): Whether MFA (Multi-Factor Authentication) is enabled.
raise_on_exception (bool): Whether to raise an exception if an error occurs.
aws_access_key_id (str): The AWS access key ID to use for the session.
aws_secret_access_key (str): The AWS secret access key to use for the session.
aws_session_token (str): The AWS session token to use for the session. Optional.
provider_id (str): The AWS account ID to validate that the provided credentials belongs to it.
Returns:
Connection: An object tha contains the result of the test connection operation.
@@ -994,9 +1249,19 @@ class AwsProvider(Provider):
Connection(is_connected=False, Error=ProfileNotFound('The config profile (not-found) could not be found'))
>>> AwsProvider.test_connection(raise_on_exception=False))
Connection(is_connected=False, Error=NoCredentialsError('Unable to locate credentials'))
>>> AwsProvider.test_connection(aws_access_key_id="XXXXXXXX", aws_secret_access_key="XXXXXXXX", raise_on_exception=False))
Connection(is_connected=True, Error=None))
>>> AwsProvider.test_connection(aws_access_key_id="XXXXXXXX", aws_secret_access_key="XXXXXXXX", provider_id="111122223333", raise_on_exception=False))
Connection(is_connected=True, Error=None))
"""
try:
session = AwsProvider.setup_session(mfa_enabled, profile)
session = AwsProvider.setup_session(
mfa=mfa_enabled,
profile=profile,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
aws_session_token=aws_session_token,
)
if role_arn:
session_duration = validate_session_duration(session_duration)
@@ -1021,62 +1286,83 @@ class AwsProvider(Provider):
profile_name=profile,
)
sts_client = AwsProvider.create_sts_session(session, aws_region)
_ = sts_client.get_caller_identity()
caller_identity = AwsProvider.validate_credentials(session, aws_region)
# Do an extra validation if the AWS account ID is provided
if provider_id and caller_identity.account != provider_id:
raise AWSInvalidProviderIdError(file=pathlib.Path(__file__).name)
return Connection(
is_connected=True,
)
except AWSSetUpSessionError as setup_session_error:
logger.error(str(setup_session_error))
logger.error(
f"{setup_session_error.__class__.__name__}[{setup_session_error.__traceback__.tb_lineno}]: {setup_session_error}"
)
if raise_on_exception:
raise setup_session_error
return Connection(error=setup_session_error)
except AWSArgumentTypeValidationError as validation_error:
logger.error(str(validation_error))
logger.error(
f"{validation_error.__class__.__name__}[{validation_error.__traceback__.tb_lineno}]: {validation_error}"
)
if raise_on_exception:
raise validation_error
return Connection(error=validation_error)
except AWSIAMRoleARNRegionNotEmtpy as arn_region_not_empty_error:
logger.error(str(arn_region_not_empty_error))
except AWSIAMRoleARNRegionNotEmtpyError as arn_region_not_empty_error:
logger.error(
f"{arn_region_not_empty_error.__class__.__name__}[{arn_region_not_empty_error.__traceback__.tb_lineno}]: {arn_region_not_empty_error}"
)
if raise_on_exception:
raise arn_region_not_empty_error
return Connection(error=arn_region_not_empty_error)
except AWSIAMRoleARNPartitionEmpty as arn_partition_empty_error:
logger.error(str(arn_partition_empty_error))
except AWSIAMRoleARNPartitionEmptyError as arn_partition_empty_error:
logger.error(
f"{arn_partition_empty_error.__class__.__name__}[{arn_partition_empty_error.__traceback__.tb_lineno}]: {arn_partition_empty_error}"
)
if raise_on_exception:
raise arn_partition_empty_error
return Connection(error=arn_partition_empty_error)
except AWSIAMRoleARNServiceNotIAMnorSTS as arn_service_not_iam_sts_error:
logger.error(str(arn_service_not_iam_sts_error))
except AWSIAMRoleARNServiceNotIAMnorSTSError as arn_service_not_iam_sts_error:
logger.error(
f"{arn_service_not_iam_sts_error.__class__.__name__}[{arn_service_not_iam_sts_error.__traceback__.tb_lineno}]: {arn_service_not_iam_sts_error}"
)
if raise_on_exception:
raise arn_service_not_iam_sts_error
return Connection(error=arn_service_not_iam_sts_error)
except AWSIAMRoleARNInvalidAccountID as arn_invalid_account_id_error:
logger.error(str(arn_invalid_account_id_error))
except AWSIAMRoleARNInvalidAccountIDError as arn_invalid_account_id_error:
logger.error(
f"{arn_invalid_account_id_error.__class__.__name__}[{arn_invalid_account_id_error.__traceback__.tb_lineno}]: {arn_invalid_account_id_error}"
)
if raise_on_exception:
raise arn_invalid_account_id_error
return Connection(error=arn_invalid_account_id_error)
except AWSIAMRoleARNInvalidResourceType as arn_invalid_resource_type_error:
logger.error(str(arn_invalid_resource_type_error))
except AWSIAMRoleARNInvalidResourceTypeError as arn_invalid_resource_type_error:
logger.error(
f"{arn_invalid_resource_type_error.__class__.__name__}[{arn_invalid_resource_type_error.__traceback__.tb_lineno}]: {arn_invalid_resource_type_error}"
)
if raise_on_exception:
raise arn_invalid_resource_type_error
return Connection(error=arn_invalid_resource_type_error)
except AWSIAMRoleARNEmptyResource as arn_empty_resource_error:
logger.error(str(arn_empty_resource_error))
except AWSIAMRoleARNEmptyResourceError as arn_empty_resource_error:
logger.error(
f"{arn_empty_resource_error.__class__.__name__}[{arn_empty_resource_error.__traceback__.tb_lineno}]: {arn_empty_resource_error}"
)
if raise_on_exception:
raise arn_empty_resource_error
return Connection(error=arn_empty_resource_error)
except AWSAssumeRoleError as assume_role_error:
logger.error(str(assume_role_error))
logger.error(
f"{assume_role_error.__class__.__name__}[{assume_role_error.__traceback__.tb_lineno}]: {assume_role_error}"
)
if raise_on_exception:
raise assume_role_error
return Connection(error=assume_role_error)
@@ -1113,11 +1399,45 @@ class AwsProvider(Provider):
) from no_credentials_error
return Connection(error=no_credentials_error)
except AWSAccessKeyIDInvalidError as access_key_id_invalid_error:
logger.error(
f"{access_key_id_invalid_error.__class__.__name__}[{access_key_id_invalid_error.__traceback__.tb_lineno}]: {access_key_id_invalid_error}"
)
if raise_on_exception:
raise access_key_id_invalid_error
return Connection(error=access_key_id_invalid_error)
except AWSSecretAccessKeyInvalidError as secret_access_key_invalid_error:
logger.error(
f"{secret_access_key_invalid_error.__class__.__name__}[{secret_access_key_invalid_error.__traceback__.tb_lineno}]: {secret_access_key_invalid_error}"
)
if raise_on_exception:
raise secret_access_key_invalid_error
return Connection(error=secret_access_key_invalid_error)
except AWSInvalidProviderIdError as invalid_account_credentials_error:
logger.error(
f"{invalid_account_credentials_error.__class__.__name__}[{invalid_account_credentials_error.__traceback__.tb_lineno}]: {invalid_account_credentials_error}"
)
if raise_on_exception:
raise invalid_account_credentials_error
return Connection(error=invalid_account_credentials_error)
except AWSSessionTokenExpiredError as session_token_expired:
logger.error(
f"{session_token_expired.__class__.__name__}[{session_token_expired.__traceback__.tb_lineno}]: {session_token_expired}"
)
if raise_on_exception:
raise session_token_expired
return Connection(error=session_token_expired)
except Exception as error:
logger.critical(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
raise error
if raise_on_exception:
raise error
return Connection(error=error)
@staticmethod
def create_sts_session(
@@ -1126,7 +1446,7 @@ class AwsProvider(Provider):
"""
Create an STS session client.
Parameters:
Args:
- session (session.Session): The AWS session object.
- aws_region (str): The AWS region to use for the session.
@@ -1150,6 +1470,59 @@ class AwsProvider(Provider):
)
raise error
@staticmethod
def get_regions(partition: Partition = Partition.aws) -> set:
"""
Get the available AWS regions from the AWS services JSON file with the ability of filtering by partition.
Args:
partition (str): The AWS partition to retrieve regions for. Defaults to "aws".
Returns:
set: A set of region names.
Raises:
AWSInvalidPartitionError: If the provided partition name is invalid.
Example:
>>> AwsProvider.get_regions("aws")
{"af-south-1"}
"""
try:
regions = set()
data = read_aws_regions_file()
if partition is None:
for service in data["services"].values():
for partition in service["regions"]:
regions.update(service["regions"][partition])
else:
partition = Partition(partition)
for service in data["services"].values():
regions.update(service["regions"][partition.value])
return regions
except ValueError as value_error:
logger.error(
f"{value_error.__class__.__name__}[{value_error.__traceback__.tb_lineno}]: {value_error}"
)
raise AWSInvalidPartitionError(
message=f"Invalid partition: {partition}",
file=os.path.basename(__file__),
)
except KeyError as key_error:
logger.error(
f"{key_error.__class__.__name__}[{key_error.__traceback__.tb_lineno}]: {key_error}"
)
raise AWSInvalidPartitionError(
message=f"Invalid partition: {partition}",
file=os.path.basename(__file__),
)
except Exception as error:
logger.error(f"{error.__class__.__name__}: {error}")
raise error
def read_aws_regions_file() -> dict:
"""
@@ -1166,29 +1539,21 @@ def read_aws_regions_file() -> dict:
return data
def get_aws_available_regions() -> set:
"""
Get the available AWS regions from the AWS services JSON file.
Returns:
set: A set of available AWS regions.
"""
try:
data = read_aws_regions_file()
regions = set()
for service in data["services"].values():
for partition in service["regions"]:
for item in service["regions"][partition]:
regions.add(item)
return regions
except Exception as error:
logger.error(f"{error.__class__.__name__}: {error}")
return set()
# TODO: This can be moved to another class since it doesn't need self
def get_aws_region_for_sts(session_region: str, regions: set[str]) -> str:
"""
Get the AWS region for the STS Assume Role operation.
Args:
- session_region (str): The region configured in the AWS session.
- regions (set[str]): The regions passed with the -f/--region/--filter-region option.
Returns:
str: The AWS region for the STS Assume Role operation
Example:
aws_region = get_aws_region_for_sts(session_region, regions)
"""
# If there is no region passed with -f/--region/--filter-region
if regions is None or len(regions) == 0:
# If you have a region configured in your AWS config or credentials file
+139 -16
View File
@@ -1145,6 +1145,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -1269,6 +1270,7 @@
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
@@ -1279,6 +1281,33 @@
],
"aws-cn": [],
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
},
"bedrock-agent": {
"regions": {
"aws": [
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-2"
],
"aws-cn": [],
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
@@ -1287,20 +1316,24 @@
"regions": {
"aws": [
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-2"
],
"aws-cn": [],
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
@@ -2594,6 +2627,7 @@
"connectcampaigns": {
"regions": {
"aws": [
"af-south-1",
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
@@ -2656,6 +2690,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -2696,6 +2731,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -3259,6 +3295,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -3943,6 +3980,7 @@
"ap-northeast-2",
"ap-northeast-3",
"ap-south-1",
"ap-south-2",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-3",
@@ -3955,6 +3993,7 @@
"eu-west-1",
"eu-west-2",
"eu-west-3",
"il-central-1",
"me-central-1",
"me-south-1",
"sa-east-1",
@@ -4361,6 +4400,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -4802,6 +4842,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -5512,6 +5553,7 @@
"iotfleetwise": {
"regions": {
"aws": [
"ap-south-1",
"eu-central-1",
"us-east-1"
],
@@ -5818,6 +5860,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -5934,6 +5977,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -6206,6 +6250,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -6795,6 +6840,7 @@
"ap-northeast-2",
"ap-northeast-3",
"ap-south-1",
"ap-south-2",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-4",
@@ -6804,6 +6850,7 @@
"eu-west-1",
"eu-west-2",
"eu-west-3",
"me-central-1",
"sa-east-1",
"us-east-1",
"us-east-2",
@@ -6942,7 +6989,10 @@
"cn-north-1",
"cn-northwest-1"
],
"aws-us-gov": []
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
},
"meteringmarketplace": {
@@ -7118,6 +7168,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -7581,15 +7632,9 @@
"opsworkscm": {
"regions": {
"aws": [
"ap-northeast-1",
"ap-southeast-1",
"ap-southeast-2",
"eu-central-1",
"eu-west-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2"
"us-east-1"
],
"aws-cn": [],
"aws-us-gov": []
@@ -8468,7 +8513,10 @@
"cn-north-1",
"cn-northwest-1"
],
"aws-us-gov": []
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
},
"rekognition": {
@@ -8481,6 +8529,7 @@
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-south-2",
"eu-west-1",
"eu-west-2",
"il-central-1",
@@ -9163,6 +9212,7 @@
"ap-southeast-3",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-north-1",
"eu-south-1",
"eu-south-2",
@@ -9217,7 +9267,6 @@
"eu-west-2",
"eu-west-3",
"il-central-1",
"me-central-1",
"me-south-1",
"sa-east-1",
"us-east-1",
@@ -9225,10 +9274,7 @@
"us-west-1",
"us-west-2"
],
"aws-cn": [
"cn-north-1",
"cn-northwest-1"
],
"aws-cn": [],
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
@@ -9390,7 +9436,10 @@
"cn-north-1",
"cn-northwest-1"
],
"aws-us-gov": []
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
},
"sdb": {
@@ -9760,6 +9809,39 @@
]
}
},
"sesv2": {
"regions": {
"aws": [
"af-south-1",
"ap-northeast-1",
"ap-northeast-2",
"ap-northeast-3",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-3",
"ca-central-1",
"eu-central-1",
"eu-north-1",
"eu-south-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"il-central-1",
"me-south-1",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2"
],
"aws-cn": [],
"aws-us-gov": [
"us-gov-east-1",
"us-gov-west-1"
]
}
},
"shield": {
"regions": {
"aws": [
@@ -9774,6 +9856,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -10142,6 +10225,30 @@
"aws-us-gov": []
}
},
"ssm-quicksetup": {
"regions": {
"aws": [
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-north-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2"
],
"aws-cn": [],
"aws-us-gov": []
}
},
"ssm-sap": {
"regions": {
"aws": [
@@ -10279,6 +10386,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -10512,6 +10620,7 @@
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-south-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
@@ -10546,6 +10655,7 @@
"regions": {
"aws": [
"ap-northeast-1",
"ap-south-1",
"ap-southeast-2",
"eu-central-1",
"eu-west-1",
@@ -10580,7 +10690,10 @@
"us-east-2",
"us-west-2"
],
"aws-cn": [],
"aws-cn": [
"cn-north-1",
"cn-northwest-1"
],
"aws-us-gov": []
}
},
@@ -10588,6 +10701,7 @@
"regions": {
"aws": [
"ap-northeast-1",
"ap-south-1",
"ap-southeast-2",
"eu-central-1",
"eu-west-1",
@@ -10666,6 +10780,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -10982,15 +11097,19 @@
"ap-northeast-2",
"ap-northeast-3",
"ap-south-1",
"ap-south-2",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-3",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-north-1",
"eu-south-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"me-central-1",
"me-south-1",
"sa-east-1",
"us-east-1",
@@ -11057,6 +11176,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -11142,6 +11262,7 @@
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ca-central-1",
"ca-west-1",
"eu-central-1",
@@ -11235,8 +11356,10 @@
"ap-northeast-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-5",
"ca-central-1",
"eu-central-1",
"eu-central-2",
"eu-north-1",
"eu-west-2",
"us-east-1"
+90 -34
View File
@@ -1,62 +1,83 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 1000 to 1999 are reserved for AWS exceptions
class AWSBaseException(ProwlerException):
"""Base class for AWS errors."""
AWS_ERROR_CODES = {
(1902, "AWSClientError"): {
(1000, "AWSClientError"): {
"message": "AWS ClientError occurred",
"remediation": "Check your AWS client configuration and permissions.",
},
(1903, "AWSProfileNotFoundError"): {
(1001, "AWSProfileNotFoundError"): {
"message": "AWS Profile not found",
"remediation": "Ensure the AWS profile is correctly configured, please visit https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html",
},
(1904, "AWSNoCredentialsError"): {
(1002, "AWSNoCredentialsError"): {
"message": "No AWS credentials found",
"remediation": "Verify that AWS credentials are properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/authentication/ and https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-configure.html",
},
(1905, "AWSArgumentTypeValidationError"): {
(1003, "AWSArgumentTypeValidationError"): {
"message": "AWS argument type validation error",
"remediation": "Check the provided argument types specific to AWS and ensure they meet the required format. For session duration check: https://docs.aws.amazon.com/singlesignon/latest/userguide/howtosessionduration.html and for role session name check: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name",
},
(1906, "AWSSetUpSessionError"): {
(1004, "AWSSetUpSessionError"): {
"message": "AWS session setup error",
"remediation": "Check the AWS session setup and ensure it is properly configured, please visit https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html and check if the provided profile has the necessary permissions.",
},
(1907, "AWSIAMRoleARNRegionNotEmtpy"): {
(1005, "AWSIAMRoleARNRegionNotEmtpyError"): {
"message": "AWS IAM Role ARN region is not empty",
"remediation": "Check the AWS IAM Role ARN region and ensure it is empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1908, "AWSIAMRoleARNPartitionEmpty"): {
(1006, "AWSIAMRoleARNPartitionEmptyError"): {
"message": "AWS IAM Role ARN partition is empty",
"remediation": "Check the AWS IAM Role ARN partition and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1909, "AWSIAMRoleARNMissingFields"): {
(1007, "AWSIAMRoleARNMissingFieldsError"): {
"message": "AWS IAM Role ARN missing fields",
"remediation": "Check the AWS IAM Role ARN and ensure all required fields are present, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1910, "AWSIAMRoleARNServiceNotIAMnorSTS"): {
(1008, "AWSIAMRoleARNServiceNotIAMnorSTSError"): {
"message": "AWS IAM Role ARN service is not IAM nor STS",
"remediation": "Check the AWS IAM Role ARN service and ensure it is either IAM or STS, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1911, "AWSIAMRoleARNInvalidAccountID"): {
(1009, "AWSIAMRoleARNInvalidAccountIDError"): {
"message": "AWS IAM Role ARN account ID is invalid",
"remediation": "Check the AWS IAM Role ARN account ID and ensure it is a valid 12-digit number, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1912, "AWSIAMRoleARNInvalidResourceType"): {
(1010, "AWSIAMRoleARNInvalidResourceTypeError"): {
"message": "AWS IAM Role ARN resource type is invalid",
"remediation": "Check the AWS IAM Role ARN resource type and ensure it is valid, resources types are: role, user, assumed-role, root, federated-user, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1913, "AWSIAMRoleARNEmptyResource"): {
(1011, "AWSIAMRoleARNEmptyResourceError"): {
"message": "AWS IAM Role ARN resource is empty",
"remediation": "Check the AWS IAM Role ARN resource and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
},
(1914, "AWSAssumeRoleError"): {
(1012, "AWSAssumeRoleError"): {
"message": "AWS assume role error",
"remediation": "Check the AWS assume role configuration and ensure it is properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/role-assumption/ and https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name",
},
(1013, "AWSAccessKeyIDInvalidError"): {
"message": "AWS Access Key ID or Session Token is invalid",
"remediation": "Check your AWS Access Key ID or Session Token and ensure it is valid.",
},
(1014, "AWSSecretAccessKeyInvalidError"): {
"message": "AWS Secret Access Key is invalid",
"remediation": "Check your AWS Secret Access Key and signing method and ensure it is valid.",
},
(1015, "AWSInvalidProviderIdError"): {
"message": "The provided AWS credentials belong to a different account",
"remediation": "Check the provided AWS credentials and review if belong to the account you want to use.",
},
(1016, "AWSSessionTokenExpiredError"): {
"message": "The provided AWS Session Token is expired",
"remediation": "Get a new AWS Session Token and configure it for the provider.",
},
(1917, "AWSInvalidPartitionError"): {
"message": "The provided AWS partition is invalid",
"remediation": "Check the provided AWS partition and ensure it is valid.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
@@ -65,7 +86,7 @@ class AWSBaseException(ProwlerException):
error_info["message"] = message
super().__init__(
code,
provider="AWS",
source="AWS",
file=file,
original_exception=original_exception,
error_info=error_info,
@@ -82,35 +103,35 @@ class AWSCredentialsError(AWSBaseException):
class AWSClientError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1902, file=file, original_exception=original_exception, message=message
1000, file=file, original_exception=original_exception, message=message
)
class AWSProfileNotFoundError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1903, file=file, original_exception=original_exception, message=message
1001, file=file, original_exception=original_exception, message=message
)
class AWSNoCredentialsError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1904, file=file, original_exception=original_exception, message=message
1002, file=file, original_exception=original_exception, message=message
)
class AWSArgumentTypeValidationError(AWSBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1905, file=file, original_exception=original_exception, message=message
1003, file=file, original_exception=original_exception, message=message
)
class AWSSetUpSessionError(AWSBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1906, file=file, original_exception=original_exception, message=message
1004, file=file, original_exception=original_exception, message=message
)
@@ -121,57 +142,92 @@ class AWSRoleArnError(AWSBaseException):
super().__init__(code, file, original_exception, message)
class AWSIAMRoleARNRegionNotEmtpy(AWSRoleArnError):
class AWSIAMRoleARNRegionNotEmtpyError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1907, file=file, original_exception=original_exception, message=message
1005, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNPartitionEmpty(AWSRoleArnError):
class AWSIAMRoleARNPartitionEmptyError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1908, file=file, original_exception=original_exception, message=message
1006, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNMissingFields(AWSRoleArnError):
class AWSIAMRoleARNMissingFieldsError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1909, file=file, original_exception=original_exception, message=message
1007, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNServiceNotIAMnorSTS(AWSRoleArnError):
class AWSIAMRoleARNServiceNotIAMnorSTSError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1910, file=file, original_exception=original_exception, message=message
1008, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNInvalidAccountID(AWSRoleArnError):
class AWSIAMRoleARNInvalidAccountIDError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1911, file=file, original_exception=original_exception, message=message
1009, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNInvalidResourceType(AWSRoleArnError):
class AWSIAMRoleARNInvalidResourceTypeError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1912, file=file, original_exception=original_exception, message=message
1010, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNEmptyResource(AWSRoleArnError):
class AWSIAMRoleARNEmptyResourceError(AWSRoleArnError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1913, file=file, original_exception=original_exception, message=message
1011, file=file, original_exception=original_exception, message=message
)
class AWSAssumeRoleError(AWSBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1914, file=file, original_exception=original_exception, message=message
1012, file=file, original_exception=original_exception, message=message
)
class AWSAccessKeyIDInvalidError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1013, file=file, original_exception=original_exception, message=message
)
class AWSSecretAccessKeyInvalidError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1014, file=file, original_exception=original_exception, message=message
)
class AWSInvalidProviderIdError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1015, file=file, original_exception=original_exception, message=message
)
class AWSSessionTokenExpiredError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1016, file=file, original_exception=original_exception, message=message
)
class AWSInvalidPartitionError(AWSBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1917, file=file, original_exception=original_exception, message=message
)
@@ -1,7 +1,7 @@
from argparse import ArgumentTypeError, Namespace
from re import fullmatch, search
from prowler.providers.aws.aws_provider import get_aws_available_regions
from prowler.providers.aws.aws_provider import AwsProvider
from prowler.providers.aws.config import ROLE_SESSION_NAME
from prowler.providers.aws.lib.arn.arn import arn_type
@@ -64,7 +64,7 @@ def init_parser(self):
"-f",
nargs="+",
help="AWS region names to run Prowler against",
choices=get_aws_available_regions(),
choices=AwsProvider.get_regions(partition=None),
)
# AWS Organizations
aws_orgs_subparser = aws_parser.add_argument_group("AWS Organizations")
+12 -12
View File
@@ -3,12 +3,12 @@ import re
from argparse import ArgumentTypeError
from prowler.providers.aws.exceptions.exceptions import (
AWSIAMRoleARNEmptyResource,
AWSIAMRoleARNInvalidAccountID,
AWSIAMRoleARNInvalidResourceType,
AWSIAMRoleARNPartitionEmpty,
AWSIAMRoleARNRegionNotEmtpy,
AWSIAMRoleARNServiceNotIAMnorSTS,
AWSIAMRoleARNEmptyResourceError,
AWSIAMRoleARNInvalidAccountIDError,
AWSIAMRoleARNInvalidResourceTypeError,
AWSIAMRoleARNPartitionEmptyError,
AWSIAMRoleARNRegionNotEmtpyError,
AWSIAMRoleARNServiceNotIAMnorSTSError,
)
from prowler.providers.aws.lib.arn.models import ARN
@@ -25,7 +25,7 @@ def parse_iam_credentials_arn(arn: str) -> ARN:
arn_parsed = ARN(arn)
# First check if region is empty (in IAM ARN's region is always empty)
if arn_parsed.region:
raise AWSIAMRoleARNRegionNotEmtpy(file=os.path.basename(__file__))
raise AWSIAMRoleARNRegionNotEmtpyError(file=os.path.basename(__file__))
else:
# check if needed fields are filled:
# - partition
@@ -34,15 +34,15 @@ def parse_iam_credentials_arn(arn: str) -> ARN:
# - resource_type
# - resource
if arn_parsed.partition is None or arn_parsed.partition == "":
raise AWSIAMRoleARNPartitionEmpty(file=os.path.basename(__file__))
raise AWSIAMRoleARNPartitionEmptyError(file=os.path.basename(__file__))
elif arn_parsed.service != "iam" and arn_parsed.service != "sts":
raise AWSIAMRoleARNServiceNotIAMnorSTS(file=os.path.basename(__file__))
raise AWSIAMRoleARNServiceNotIAMnorSTSError(file=os.path.basename(__file__))
elif (
arn_parsed.account_id is None
or len(arn_parsed.account_id) != 12
or not arn_parsed.account_id.isnumeric()
):
raise AWSIAMRoleARNInvalidAccountID(file=os.path.basename(__file__))
raise AWSIAMRoleARNInvalidAccountIDError(file=os.path.basename(__file__))
elif (
arn_parsed.resource_type != "role"
and arn_parsed.resource_type != "user"
@@ -50,9 +50,9 @@ def parse_iam_credentials_arn(arn: str) -> ARN:
and arn_parsed.resource_type != "root"
and arn_parsed.resource_type != "federated-user"
):
raise AWSIAMRoleARNInvalidResourceType(file=os.path.basename(__file__))
raise AWSIAMRoleARNInvalidResourceTypeError(file=os.path.basename(__file__))
elif arn_parsed.resource == "":
raise AWSIAMRoleARNEmptyResource(file=os.path.basename(__file__))
raise AWSIAMRoleARNEmptyResourceError(file=os.path.basename(__file__))
else:
return arn_parsed
+2 -2
View File
@@ -3,7 +3,7 @@ from typing import Optional
from pydantic import BaseModel
from prowler.providers.aws.exceptions.exceptions import AWSIAMRoleARNMissingFields
from prowler.providers.aws.exceptions.exceptions import AWSIAMRoleARNMissingFieldsError
class ARN(BaseModel):
@@ -19,7 +19,7 @@ class ARN(BaseModel):
# Validate the ARN
## Check that arn starts with arn
if not arn.startswith("arn:"):
raise AWSIAMRoleARNMissingFields(file=os.path.basename(__file__))
raise AWSIAMRoleARNMissingFieldsError(file=os.path.basename(__file__))
## Retrieve fields
arn_elements = arn.split(":", 5)
data = {
@@ -0,0 +1,77 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 6000 to 6999 are reserved for S3 exceptions
class S3BaseException(ProwlerException):
"""Base class for S3 exceptions."""
S3_ERROR_CODES = {
(6000, "S3TestConnectionError"): {
"message": "Failed to test connection to S3 bucket.",
"remediation": "Check the S3 bucket name and permissions.",
},
(6001, "S3InvalidBucketNameError"): {
"message": "The specified S3 bucket name is invalid.",
"remediation": "Check the S3 bucket name.",
},
(6002, "S3BucketAccessDeniedError"): {
"message": "Access to the specified S3 bucket is denied.",
"remediation": "Check the S3 bucket permissions.",
},
(6003, "S3ClientError"): {
"message": "An error occurred while interacting with the S3 client.",
"remediation": "Check the S3 client configuration.",
},
(6004, "S3IllegalLocationConstraintError"): {
"message": "The specified location constraint is not valid.",
"remediation": "Check the location constraint.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
module = "S3"
error_info = self.S3_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code=code,
source=module,
file=file,
original_exception=original_exception,
error_info=error_info,
)
class S3TestConnectionError(S3BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6000, file=file, original_exception=original_exception, message=message
)
class S3InvalidBucketNameError(S3BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6001, file=file, original_exception=original_exception, message=message
)
class S3BucketAccessDeniedError(S3BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6002, file=file, original_exception=original_exception, message=message
)
class S3ClientError(S3BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6003, file=file, original_exception=original_exception, message=message
)
class S3IllegalLocationConstraintError(S3BaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
6004, file=file, original_exception=original_exception, message=message
)
+90
View File
@@ -1,10 +1,20 @@
import tempfile
from os import path
from tempfile import NamedTemporaryFile
from boto3 import Session
from botocore import exceptions
from prowler.lib.logger import logger
from prowler.lib.outputs.output import Output
from prowler.providers.aws.lib.s3.exceptions.exceptions import (
S3BucketAccessDeniedError,
S3ClientError,
S3IllegalLocationConstraintError,
S3InvalidBucketNameError,
S3TestConnectionError,
)
from prowler.providers.common.models import Connection
class S3:
@@ -147,3 +157,83 @@ class S3:
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
return uploaded_objects
@staticmethod
def test_connection(
session, bucket_name: str, raise_on_exception: bool = True
) -> Connection:
"""
Test the connection to the S3 bucket.
Parameters:
- session: An instance of the `Session` class representing the AWS session.
- bucket_name: A string representing the name of the S3 bucket.
- raise_on_exception: A boolean indicating whether to raise an exception if the connection test fails.
Returns:
- A Connection object indicating the status of the connection test.
Raises:
- Exception: An exception indicating that the connection test failed.
"""
try:
s3_client = session.client(__class__.__name__.lower())
if "s3://" in bucket_name:
bucket_name = bucket_name.removeprefix("s3://")
# Check for the bucket location
bucket_location = s3_client.get_bucket_location(Bucket=bucket_name)
if bucket_location["LocationConstraint"] == "EU":
bucket_location["LocationConstraint"] = "eu-west-1"
if (
bucket_location["LocationConstraint"] == ""
or bucket_location["LocationConstraint"] is None
):
bucket_location["LocationConstraint"] = "us-east-1"
# If the bucket location is not the same as the session region, change the session region
if (
session.region_name != bucket_location["LocationConstraint"]
and bucket_location["LocationConstraint"] is not None
):
s3_client = session.client(
__class__.__name__.lower(),
region_name=bucket_location["LocationConstraint"],
)
# Set a Temp file to upload
with tempfile.TemporaryFile() as temp_file:
temp_file.write(b"Test Prowler Connection")
temp_file.seek(0)
s3_client.upload_fileobj(
temp_file, bucket_name, "test-prowler-connection.txt"
)
# Try to delete the file
s3_client.delete_object(
Bucket=bucket_name, Key="test-prowler-connection.txt"
)
return Connection(is_connected=True)
except exceptions.ClientError as client_error:
if raise_on_exception:
if (
"specified bucket does not exist"
in client_error.response["Error"]["Message"]
):
raise S3InvalidBucketNameError(original_exception=client_error)
elif (
"IllegalLocationConstraintException"
in client_error.response["Error"]["Message"]
):
raise S3IllegalLocationConstraintError(
original_exception=client_error
)
elif "AccessDenied" in client_error.response["Error"]["Code"]:
raise S3BucketAccessDeniedError(original_exception=client_error)
else:
raise S3ClientError(original_exception=client_error)
return Connection(is_connected=False, error=client_error)
except Exception as error:
if raise_on_exception:
raise S3TestConnectionError(original_exception=error)
return False
@@ -0,0 +1,44 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 7000 to 7999 are reserved for Security Hub exceptions
class SecurityHubBaseException(ProwlerException):
"""Base class for Security Hub exceptions."""
SECURITYHUB_ERROR_CODES = {
(7000, "SecurityHubNoEnabledRegionsError"): {
"message": "No regions were found to with the Security Hub integration enabled.",
"remediation": "Please check the connection settings and permissions and try again.",
},
(7001, "SecurityHubInvalidRegionError"): {
"message": "Given region has not Security Hub enabled.",
"remediation": "Please provide a valid region.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
module = "SecurityHub"
error_info = self.SECURITYHUB_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code=code,
source=module,
file=file,
original_exception=original_exception,
error_info=error_info,
)
class SecurityHubNoEnabledRegionsError(SecurityHubBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
7000, file=file, original_exception=original_exception, message=message
)
class SecurityHubInvalidRegionError(SecurityHubBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
7001, file=file, original_exception=original_exception, message=message
)
@@ -1,14 +1,35 @@
from dataclasses import dataclass
from boto3 import Session
from botocore.client import ClientError
from prowler.config.config import timestamp_utc
from prowler.lib.logger import logger
from prowler.lib.outputs.asff.asff import AWSSecurityFindingFormat
from prowler.providers.aws.aws_provider import AwsProvider
from prowler.providers.aws.lib.security_hub.exceptions.exceptions import (
SecurityHubInvalidRegionError,
SecurityHubNoEnabledRegionsError,
)
from prowler.providers.common.models import Connection
SECURITY_HUB_INTEGRATION_NAME = "prowler/prowler"
SECURITY_HUB_MAX_BATCH = 100
@dataclass
class SecurityHubConnection(Connection):
"""
Represents a Security Hub connection object.
Attributes:
enabled_regions (set): Set of regions where Security Hub is enabled.
disabled_regions (set): Set of regions where Security Hub is disabled.
"""
enabled_regions: set = None
disabled_regions: set = None
class SecurityHub:
"""
Class representing a SecurityHub object for managing findings and interactions with AWS Security Hub.
@@ -53,7 +74,10 @@ class SecurityHub:
if aws_security_hub_available_regions:
self._enabled_regions = self.verify_enabled_per_region(
aws_security_hub_available_regions
aws_security_hub_available_regions,
aws_session,
aws_account_id,
aws_partition,
)
if findings and self._enabled_regions:
self._findings_per_region = self.filter(findings, send_only_fails)
@@ -103,9 +127,12 @@ class SecurityHub:
)
return findings_per_region
@staticmethod
def verify_enabled_per_region(
self,
aws_security_hub_available_regions: list[str],
session: Session,
aws_account_id: str,
aws_partition: str,
) -> dict[str, Session]:
"""
Filters the given list of regions where AWS Security Hub is enabled and returns a dictionary containing the region and their boto3 client if the region and the Prowler integration is enabled.
@@ -123,13 +150,11 @@ class SecurityHub:
f"Checking if the {SECURITY_HUB_INTEGRATION_NAME} is enabled in the {region} region."
)
# Check if security hub is enabled in current region
security_hub_client = self._session.client(
"securityhub", region_name=region
)
security_hub_client = session.client("securityhub", region_name=region)
security_hub_client.describe_hub()
# Check if Prowler integration is enabled in Security Hub
security_hub_prowler_integration_arn = f"arn:{self._aws_partition}:securityhub:{region}:{self._aws_account_id}:product-subscription/{SECURITY_HUB_INTEGRATION_NAME}"
security_hub_prowler_integration_arn = f"arn:{aws_partition}:securityhub:{region}:{aws_account_id}:product-subscription/{SECURITY_HUB_INTEGRATION_NAME}"
if security_hub_prowler_integration_arn not in str(
security_hub_client.list_enabled_products_for_import()
):
@@ -137,7 +162,7 @@ class SecurityHub:
f"Security Hub is enabled in {region} but Prowler integration does not accept findings. More info: https://docs.prowler.cloud/en/latest/tutorials/aws/securityhub/"
)
else:
enabled_regions[region] = self._session.client(
enabled_regions[region] = session.client(
"securityhub", region_name=region
)
@@ -148,7 +173,7 @@ class SecurityHub:
error_message = client_error.response["Error"]["Message"]
if (
error_code == "InvalidAccessException"
and f"Account {self._aws_account_id} is not subscribed to AWS Security Hub"
and f"Account {aws_account_id} is not subscribed to AWS Security Hub"
in error_message
):
logger.warning(
@@ -284,3 +309,104 @@ class SecurityHub:
f"{error.__class__.__name__} -- [{error.__traceback__.tb_lineno}]:{error} in region {region}"
)
return success_count
@staticmethod
def test_connection(
session: Session,
aws_account_id: str,
aws_partition: str,
regions: set = None,
raise_on_exception: bool = True,
) -> SecurityHubConnection:
"""
Test the connection to AWS Security Hub by checking if Security Hub is enabled in the provided region
and if the Prowler integration is active.
Args:
session (Session): AWS session to use for authentication.
regions (set): Set of regions to check for Security Hub integration.
aws_account_id (str): AWS account ID to check for Prowler integration.
aws_partition (str): AWS partition (e.g., aws, aws-cn, aws-us-gov).
raise_on_exception (bool): Whether to raise an exception if an error occurs.
Returns:
Connection: An object that contains the result of the test connection operation.
- is_connected (bool): Indicates whether the connection was successful.
- error (Exception): An exception object if an error occurs during the connection test.
enabled_regions (set): Set of regions where Security Hub is enabled.
disabled_regions (set): Set of regions where Security Hub is disabled.
"""
try:
disabled_regions = set()
enabled_regions = set()
all_regions = AwsProvider.get_available_aws_service_regions(
service="securityhub", partition=aws_partition
)
enabled_regions = SecurityHub.verify_enabled_per_region(
aws_security_hub_available_regions=all_regions,
session=session,
aws_account_id=aws_account_id,
aws_partition=aws_partition,
).keys()
disabled_regions = all_regions - enabled_regions
if regions:
if not any(region in enabled_regions for region in regions):
logger.warning(
f"Prowler integration is not enabled in regions: {regions - enabled_regions}."
)
invalid_region_error = SecurityHubInvalidRegionError(
message="Given regions have not Security Hub enabled."
)
if raise_on_exception:
raise invalid_region_error
return SecurityHubConnection(
is_connected=False,
error=invalid_region_error,
enabled_regions=enabled_regions,
disabled_regions=disabled_regions,
)
else:
logger.info(
f"Prowler integration is enabled in regions: {', '.join(regions)}."
)
return SecurityHubConnection(
is_connected=True,
error=None,
enabled_regions=enabled_regions,
disabled_regions=disabled_regions,
)
if len(enabled_regions) == 0:
error_str = (
"No regions found with the Security Hub integration enabled."
)
logger.warning(error_str)
no_enabled_regions_error = SecurityHubNoEnabledRegionsError(
message=error_str
)
if raise_on_exception:
raise no_enabled_regions_error
return SecurityHubConnection(
is_connected=False,
error=no_enabled_regions_error,
enabled_regions=enabled_regions,
disabled_regions=disabled_regions,
)
else:
logger.info(
f"Security Hub is enabled in the following regions: {', '.join(enabled_regions)}."
)
return SecurityHubConnection(
is_connected=True,
error=None,
enabled_regions=enabled_regions,
disabled_regions=disabled_regions,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
raise error
Loaded 100 of 1029 files, more files were not shown because too many files have changed in this diff. Show more