Compare commits

..

127 Commits

Author SHA1 Message Date
Sergio Garcia 9c9d270053 fix(ulimit): import library only in windows (#3738) 2024-04-09 15:36:05 +02:00
Pedro Martín f7fab165ba fix(aws_lambda): Update obsolete lambda runtimes (#3735) 2024-04-09 15:08:19 +02:00
Pepe Fagoaga 93bdf43c95 fix(actions): Don't need expressions within if (#3733) 2024-04-09 13:33:53 +02:00
Pepe Fagoaga b3866b5b71 docs(dashboard): format list (#3732) 2024-04-09 13:18:52 +02:00
Sergio Garcia 2308084dee chore(version): update Prowler version (#3730) 2024-04-09 13:18:00 +02:00
Pepe Fagoaga 6eb5496c27 docs(dashboard): Indicate how to change port (#3729) 2024-04-09 12:28:54 +02:00
Nacho Rivera c5514fdb63 chore(regions_update): Changes in regions for AWS services. (#3727)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-04-09 12:03:06 +02:00
Pedro Martín c78c3058fd fix(service_name): fix typo in ServiceName field (#3723) 2024-04-09 11:39:02 +02:00
Pepe Fagoaga 10d9ef9906 chore(dispatch): just for v3 (#3712) 2024-04-09 11:33:00 +02:00
Pepe Fagoaga 43426041ef docs(mutelist): remove MUTED and explain new fields (#3726) 2024-04-09 11:18:07 +02:00
Sergio Garcia 125eb9ac53 fix(k8s): improve kubernetes deployment (#3713) 2024-04-09 10:45:58 +02:00
Pedro Martín 681407e0a2 fix(compliance): add field ModoEjecucion in csv output for ENS (#3719) 2024-04-09 10:26:06 +02:00
Pedro Martín 082f3a8fe8 fix(dashboard): Add multiple dashboard fixes (#3714) 2024-04-09 10:22:03 +02:00
Sergio Garcia 397cc26b2a fix(gcp): add project id to outputs (#3711) 2024-04-09 10:17:32 +02:00
Rubén De la Torre Vico 331ae92843 chore(Azure): Optimize Entra service to use async funcs (#3706) 2024-04-09 09:20:06 +02:00
dependabot[bot] 06843cd41a chore(deps): bump botocore from 1.34.77 to 1.34.80 (#3715)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-09 08:39:56 +02:00
Pedro Martín 28b5ef9ee9 fix(ens): add dependencias field ENS rd2022 compliance (#3701) 2024-04-09 08:29:41 +02:00
Pedro Martín 63dcc057d3 feat(dashboard): add correct label for each dropdown (#3700) 2024-04-08 17:50:48 +02:00
Sergio Garcia 0bc16ee5ff chore(Dockerfile): remove deprecated dash dependencies (#3708) 2024-04-08 14:58:19 +02:00
Sergio Garcia abcc9c2c80 docs(images): fix images link in documentation (#3709) 2024-04-08 14:49:06 +02:00
Sergio Garcia daf2ad38bd chore(docs): update CloudShell scripts (#3687) 2024-04-08 14:39:29 +02:00
Sergio Garcia 3dc418df39 chore(action): update python version to 3.12 in GH action (#3705) 2024-04-08 12:48:54 +02:00
dependabot[bot] 00aaafbc12 chore(deps-dev): bump moto from 5.0.4 to 5.0.5 (#3681)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-08 12:47:22 +02:00
Sergio Garcia bd49a55f3d chore(Dockerfile): update Python version to 3.12 (#3699) 2024-04-08 12:22:49 +02:00
dependabot[bot] 013975b7a6 chore(deps): bump kubernetes from 28.1.0 to 29.0.0 (#3679)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-08 12:21:23 +02:00
Pepe Fagoaga 392026286a fix(actions): use LATEST_TAG for v4 (#3703) 2024-04-08 12:10:02 +02:00
Nacho Rivera 29ef974565 chore(regions_update): Changes in regions for AWS services. (#3693)
Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com>
2024-04-08 11:52:51 +02:00
Sergio Garcia 06c8216092 build(deps): Update boto3 to version 1.34.77 (#3669)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-04-08 11:51:22 +02:00
Pepe Fagoaga 03f04d24a5 chore(dependabot): Add v3 label (#3698) 2024-04-08 11:19:35 +02:00
Pedro Martín 7b45ed63cc docs(dashboard): improve dashboard documentation (#3688) 2024-04-08 11:10:30 +02:00
Sergio Garcia 6e4dd1d69c fix(k8s): sanitize context syntax only for output file names (#3689) 2024-04-08 11:08:35 +02:00
Sergio Garcia 185b4cba0c chore(mutelist): remove space within mutelist name (#3690) 2024-04-08 11:07:29 +02:00
Pepe Fagoaga 8198ea4a2c chore(dependabot): Run also for v3 branch (#3683) 2024-04-08 11:05:09 +02:00
dependabot[bot] aaf3e8a5cf chore(deps): bump google-api-python-client from 2.124.0 to 2.125.0 (#3678)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-08 10:55:00 +02:00
dependabot[bot] ecef56fa8f chore(deps): bump trufflesecurity/trufflehog from 3.71.2 to 3.72.0 (#3677)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-08 10:39:53 +02:00
Pepe Fagoaga 349ce3f2d0 chore(regions): Add backport-v3 label (#3684) 2024-04-08 10:31:28 +02:00
Sergio Garcia e3d4741213 chore(merge): include latest changes of v3 (#3686)
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 <rubendltv22@gmail.com>
Co-authored-by: Nacho Rivera <nachor1992@gmail.com>
2024-04-08 10:30:39 +02:00
Pepe Fagoaga 9d6d5f1d76 fix(args): Handle default argument (#3674) 2024-04-08 10:01:35 +02:00
Pepe Fagoaga 3152d67f58 chore(actions): Run for master and v3 (#3685) 2024-04-08 09:35:23 +02:00
Pepe Fagoaga cb41c8d15b fix(dockerfile): add missing path to build (#3680) 2024-04-08 09:24:05 +02:00
Pepe Fagoaga 06590842d6 chore(action): Run for v4 branch (#3666) 2024-04-04 15:53:45 +02:00
Pedro Martín d4c22a0ca5 fix(dashboard): handle Kubernetes CIS in EKS context (#3671) 2024-04-04 15:50:38 +02:00
Sergio Garcia c6f9936292 fix(merge): update v4 with latest changes (#3670) 2024-04-04 15:37:41 +02:00
Sergio Garcia eaa8900758 fix(threat detection): rename to threshold (#3665) 2024-04-04 13:29:35 +02:00
Pedro Martín e1e95d8879 docs(Dashboard): Add docs for dashboards (#3655) 2024-04-04 13:26:42 +02:00
Pedro Martín ef3a0f4878 fix(Dashboard): Multiple dashboard fixes (#3654)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-04-04 13:14:27 +02:00
Sergio Garcia 64cc36e7e2 fix(fixer): list fixers without sufix (#3660)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-04-04 13:07:54 +02:00
Sergio Garcia 1e001bb0fd fix(deps): solve dependencies (#3662) 2024-04-04 12:48:59 +02:00
Sergio Garcia 6ba123a003 fix(box): remove lines inside box (#3657) 2024-04-04 12:24:14 +02:00
Pepe Fagoaga 36d0f2c23f fix: typo in action (#3659) 2024-04-04 12:04:45 +02:00
Sergio Garcia 63412e3645 chore(merge): update v4 with latest changes of v3 (#3653) 2024-04-03 18:31:36 +02:00
Pedro Martín 191cf276c3 feat(dashboards): add new Prowler dashboards (#3575)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-04-02 18:12:16 +02:00
Sergio Garcia 45978bd0bb feat(fixer): add Prowler Fixer feature! (#3634) 2024-04-02 17:13:26 +02:00
Sergio Garcia 9666652d18 chore(readme): update k8s cis (#3640) 2024-04-02 14:37:20 +02:00
Sergio Garcia ad2716d7c9 chore(compliance): only execute all compliances in normal execution (#3635) 2024-04-02 10:55:38 +02:00
Sergio Garcia 0a7939bea3 chore(args): add plural severity argument (#3636) 2024-04-02 10:21:42 +02:00
Sergio Garcia b8c50a7b45 chore(backport): merge changes from v3 to v4 (#3625)
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 <rubendltv22@gmail.com>
Co-authored-by: Nacho Rivera <nachor1992@gmail.com>
Co-authored-by: Gabriel Soltz <8935378+gabrielsoltz@users.noreply.github.com>
Co-authored-by: Hugo966 <148140670+Hugo966@users.noreply.github.com>
Co-authored-by: Kay Agahd <kagahd@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-04-02 08:52:21 +02:00
Sergio Garcia 175e8d2b05 chore(slogan): update Prowler slogan (#3619) 2024-04-01 12:19:14 +02:00
Pepe Fagoaga 046069a656 chore(categories): Add threat detection checks in the loader (#3622) 2024-04-01 11:48:46 +02:00
Sergio Garcia f9522da48f feat(cloudtrail): add threat detection checks for AWS (enum and priv escalation) (#3602) 2024-03-27 16:23:00 +01:00
Sergio Garcia c03f959005 chore(ulimit): handle low ulimit value on shell session for POSIX if max open files is below 4096 (#3601) 2024-03-27 14:52:14 +01:00
Sergio Garcia 522aeebe5e chore(args): sanitize arguments (#3611) 2024-03-27 14:14:21 +01:00
Sergio Garcia 5312f487f9 chore(report): improve shown report in UI (#3587) 2024-03-27 12:57:20 +01:00
Pedro Martín d9b6624d65 feat(compliance): Add CIS 1.8 framework for Kubernetes (#3600)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-26 14:03:39 +01:00
Hugo966 1506da54fc feat(azure): locations added to Azure findings (#3596) 2024-03-22 15:41:58 +01:00
Sergio Garcia 245512d320 fix(providers): import modules also from outside of directory (#3595) 2024-03-22 13:36:21 +01:00
Pepe Fagoaga 487190b379 fix(securityhub): Add validation and handle errors (#3590)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-22 10:27:48 +01:00
Sergio Garcia 74aaeaa95c fix(mapping): handle None attributes in data (#3588)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-03-21 17:56:21 +01:00
Sergio Garcia 28e8f0de2b chore(merge): get latest changes from v3 to v4 (#3582)
Co-authored-by: Hugo966 <148140670+Hugo966@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Nacho Rivera <nachor1992@gmail.com>
2024-03-21 17:08:19 +01:00
Pedro Martín f60b5017e2 fix(compliance): fix csv output for framework Mitre Attack (#3574) 2024-03-21 13:18:03 +01:00
Sergio Garcia fe80821596 chore(muted): handle new Muted status (#3570) 2024-03-19 18:37:49 +01:00
Pepe Fagoaga 628a3c4e7b fix(quickinventory): Adapt for the new AWS provider class (#3569)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-19 16:14:01 +01:00
Sergio Garcia 3d59c34ec9 chore(merge): add new changes from v3 (#3549)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
Co-authored-by: Nacho Rivera <nachor1992@gmail.com>
Co-authored-by: Rubén De la Torre Vico <rubendltv22@gmail.com>
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
Co-authored-by: Hugo966 <148140670+Hugo966@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hugo Gálvez Ureña <hugogalvezu96@gmail.com>
Co-authored-by: github-actions <noreply@github.com>
2024-03-19 15:54:41 +01:00
Sergio Garcia 35043c2dd6 chore(unused services): scan unused services by default and add flag (#3556)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-03-19 15:15:19 +01:00
Pepe Fagoaga ab815123c9 chore(slack): fix integration with provider (#3565)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-19 11:24:11 +01:00
Pepe Fagoaga 69ab84efe1 chore(main): remove getattr for mutelist (#3564) 2024-03-19 10:58:02 +01:00
Pepe Fagoaga 77823afa54 chore(audit_info): Replace for provider and add tests (#3542)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-19 09:53:05 +01:00
Pepe Fagoaga 63cd6c1290 chore(mutelist): enforce for all providers (#3554) 2024-03-18 10:12:15 +01:00
Sergio Garcia cab32d2f94 feat(mutelist): add Mute List for all providers (#3548) 2024-03-15 12:22:10 +01:00
Pepe Fagoaga 1f4316e9dd chore(ocsf): add OCSF 1.1 and organize code (#3517)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-14 15:04:47 +01:00
Pepe Fagoaga ade762a85e fix(azure): use subscriptions in get_locations (#3541) 2024-03-14 14:57:20 +01:00
Pepe Fagoaga bda5d62c72 chore(aws): Replace audit_info for provider (#3521)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-13 18:15:24 +01:00
Pepe Fagoaga 2176fff8c3 chore(json): deprecate native json (#3514) 2024-03-13 18:11:33 +01:00
Pepe Fagoaga 87893bd54b chore(csv): Common output for all the providers (#3513)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-13 17:31:35 +01:00
Sergio Garcia b539a888b1 chore(compliance): solve compliance issues (#3507)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-03-13 15:43:33 +01:00
Sergio Garcia d6b2b0ca13 docs(kubernetes): add Kubernetes documentation (#3482) 2024-03-13 15:37:49 +01:00
Pepe Fagoaga 58ee45b702 chore(merge): 2024-03-06 11:03:00 UTC (#3506) 2024-03-06 13:05:31 +01:00
Pepe Fagoaga c62d97f23a chore(html): deprecate output (#3501)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-05 14:16:23 +01:00
Pepe Fagoaga d618c5ea12 fix(shodan): Make it available for all the providers (#3500) 2024-03-05 13:55:43 +01:00
Pepe Fagoaga d8e27f0d33 chore(config): Store in provider (#3498)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-05 10:21:08 +01:00
Sergio Garcia 38496ff646 chore(kubernetes): add outputs fields (#3499) 2024-03-05 10:01:51 +01:00
Pepe Fagoaga da1084907e chore(providers): Store output options and mutelist (#3497) 2024-03-05 09:56:30 +01:00
Pepe Fagoaga 3385b630e7 chore(azure): working outputs (#3491)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-04 17:59:48 +01:00
Pepe Fagoaga fc59183045 chore(gcp): working outputs (#3490)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-04 17:54:41 +01:00
Pepe Fagoaga 33242079f7 chore(k8s): Working outputs (#3489) 2024-03-04 17:25:14 +01:00
Pepe Fagoaga 086148819c chore(aws): Working outputs (#3488) 2024-03-04 17:17:20 +01:00
Pepe Fagoaga 5df9fd881c chore(aws): Simplify provider (#3481)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-03-04 13:50:54 +01:00
Pepe Fagoaga bd17d36e7f chore(kubernetes): Working provider (#3475)
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-01 14:10:10 +01:00
Pepe Fagoaga be55fa22fd chore(azure): working version executing checks (#3474) 2024-03-01 13:30:09 +01:00
Pepe Fagoaga b48b3a5e2e chore(azure): working version executing checks (#3472)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-03-01 11:33:01 +01:00
Sergio Garcia fc03dd37f1 chore(kubernetes): enhance checks metadata (#3469) 2024-02-29 17:16:28 +01:00
Sergio Garcia d8bb384689 chore(kubernetes): add strong ciphers config vars (#3470) 2024-02-29 14:48:21 +01:00
Pepe Fagoaga 0b32a10bb8 chore(aws): Remove old provider (#3468) 2024-02-29 13:45:43 +01:00
Pepe Fagoaga f0c027f54e chore(merge): Merge master with Prowler 4.0 (#3467)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
2024-02-29 11:19:17 +01:00
Sergio Garcia b0f2f34d3b feat(namespace): add --namespaces argument and solve bugs (#3431) 2024-02-28 19:33:29 +01:00
Sergio Garcia 3e6b76df76 fix(kubernetes): improve in-cluster execution (#3397) 2024-02-28 19:00:33 +01:00
Sergio Garcia 6197cf792d feat(kubelet): add 6 checks of Kubelet configuration files on the worker nodes (#3335)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-28 18:32:45 +01:00
Sergio Garcia 3c4e5a14f7 feat(core): add 13 checks of Kubernetes Core service (#3315)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-28 13:21:53 +01:00
Sergio Garcia effc743b6e feat(rbac): add 9 checks of Kubernetes RBAC service (#3314) 2024-02-27 13:54:46 +01:00
Sergio Garcia 364a945d28 feat(kubelet): add 10 checks of Kubernetes Kubelet service (#3302)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-26 14:15:35 +01:00
Sergio Garcia 07b9354d18 feat(etcd): add checks for Kubernetes etcd (#3294)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-22 16:45:06 +00:00
Sergio Garcia 8b1e537ca5 feat(controllermanager): add checks for Kubernetes Controller Manager (#3291) 2024-02-22 16:55:23 +01:00
Sergio Garcia 6a20e850bc feat(apiserver): new 10 Kubernetes ApiServer checks (#3290) 2024-02-22 10:50:12 +01:00
Sergio Garcia 636892bc9a feat(apiserver): new 10 Kubernetes ApiServer checks (#3289) 2024-02-21 13:29:28 +01:00
Sergio Garcia b40f32ab57 feat(apiserver): new 9 Kubernetes ApiServer checks (#3288)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-21 09:19:50 +01:00
Sergio Garcia 14bab496b5 chore(tests): add kubernetes provider tests (#3265) 2024-02-19 12:50:42 +00:00
Sergio Garcia 3cc367e0a3 feat(kubernetes): add etcd, controllermanager and rbac services (#3261)
Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
2024-02-19 13:19:07 +01:00
Nacho Rivera 36fc575e40 feat(AwsProvider): include new structure for AWS provider (#3252)
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
2024-01-15 16:55:53 +01:00
Sergio Garcia 24efb34d91 chore(manual status): change INFO to MANUAL status (#3254) 2024-01-09 18:08:00 +01:00
Sergio Garcia c08e244c95 feat(status): add --status flag (#3238) 2024-01-09 11:35:44 +01:00
Sergio Garcia c2f8980f1f feat(kubernetes): add Kubernetes provider (#3226)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
2024-01-09 10:31:51 +01:00
Sergio Garcia 0ef85b3dee fix(gcp): fix error in generating compliance (#3201) 2023-12-18 12:10:58 +01:00
Sergio Garcia 93a2431211 feat(compliance): execute all compliance by default (#3003)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
2023-12-13 17:31:39 +01:00
Nacho Rivera 1fe74937c1 feat(CloudProvider): introduce global provider Azure&GCP (#3069) 2023-12-12 18:05:17 +01:00
Sergio Garcia 6ee016e577 chore(sts-endpoint): deprecate --sts-endpoint-region (#3046)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
2023-12-12 17:13:50 +01:00
Sergio Garcia f7248dfb1c feat(mute list): change allowlist to mute list (#3039)
Co-authored-by: Nacho Rivera <nachor1992@gmail.com>
2023-12-12 16:57:52 +01:00
Nacho Rivera 856afb3966 chore(update): rebase from master (#3067)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: r3drun3 <simone.ragonesi@sighup.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Mastron <14130495+mtronrd@users.noreply.github.com>
Co-authored-by: John Mastron <jmastron@jpl.nasa.gov>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
Co-authored-by: sergargar <sergargar@users.noreply.github.com>
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
Co-authored-by: github-actions <noreply@github.com>
Co-authored-by: simone ragonesi <102741679+R3DRUN3@users.noreply.github.com>
Co-authored-by: Johnny Lu <johnny2lu@gmail.com>
Co-authored-by: Vajrala Venkateswarlu <59252985+venkyvajrala@users.noreply.github.com>
Co-authored-by: Ignacio Dominguez <ignacio.dominguez@zego.com>
2023-11-27 13:58:45 +01:00
1607 changed files with 61992 additions and 17062 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
name: 💡 Feature Request
description: Suggest an idea for this project
labels: ["enhancement", "status/needs-triage"]
labels: ["feature-request", "status/needs-triage"]
body:
+21 -2
View File
@@ -5,8 +5,8 @@
version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
target-branch: master
@@ -18,3 +18,22 @@ updates:
schedule:
interval: "weekly"
target-branch: master
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
target-branch: v3
labels:
- "dependencies"
- "pip"
- "v3"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
target-branch: v3
labels:
- "github_actions"
- "v3"
@@ -0,0 +1,24 @@
name: Pull Request Documentation Link
on:
pull_request:
branches:
- 'master'
- 'v3'
paths:
- 'docs/**'
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
jobs:
documentation-link:
name: Documentation Link
runs-on: ubuntu-latest
steps:
- name: Leave PR comment with the SaaS Documentation URI
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ env.PR_NUMBER }}
body: |
You can check the documentation for this PR here -> [SaaS Documentation](https://prowler-prowler-docs--${{ env.PR_NUMBER }}.com.readthedocs.build/projects/prowler-open-source/en/${{ env.PR_NUMBER }}/)
@@ -3,6 +3,7 @@ name: build-lint-push-containers
on:
push:
branches:
- "v3"
- "master"
paths-ignore:
- ".github/**"
@@ -13,44 +14,90 @@ on:
types: [published]
env:
# AWS Configuration
AWS_REGION_STG: eu-west-1
AWS_REGION_PLATFORM: eu-west-1
AWS_REGION: us-east-1
# Container's configuration
IMAGE_NAME: prowler
DOCKERFILE_PATH: ./Dockerfile
# Tags
LATEST_TAG: latest
STABLE_TAG: stable
TEMPORARY_TAG: temporary
DOCKERFILE_PATH: ./Dockerfile
PYTHON_VERSION: 3.9
# The RELEASE_TAG is set during runtime in releases
RELEASE_TAG: ""
# The PROWLER_VERSION and PROWLER_VERSION_MAJOR are set during runtime in releases
PROWLER_VERSION: ""
PROWLER_VERSION_MAJOR: ""
# TEMPORARY_TAG: temporary
# Python configuration
PYTHON_VERSION: 3.12
jobs:
# Build Prowler OSS container
container-build-push:
# needs: dockerfile-linter
runs-on: ubuntu-latest
outputs:
prowler_version_major: ${{ steps.get-prowler-version.outputs.PROWLER_VERSION_MAJOR }}
prowler_version: ${{ steps.update-prowler-version.outputs.PROWLER_VERSION }}
env:
POETRY_VIRTUALENVS_CREATE: "false"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup python (release)
if: github.event_name == 'release'
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies (release)
if: github.event_name == 'release'
- name: Install Poetry
run: |
pipx install poetry
pipx inject poetry poetry-bumpversion
- name: Get Prowler version
id: get-prowler-version
run: |
PROWLER_VERSION="$(poetry version -s 2>/dev/null)"
# Store prowler version major just for the release
PROWLER_VERSION_MAJOR="${PROWLER_VERSION%%.*}"
echo "PROWLER_VERSION_MAJOR=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_ENV}"
echo "PROWLER_VERSION_MAJOR=${PROWLER_VERSION_MAJOR}" >> "${GITHUB_OUTPUT}"
case ${PROWLER_VERSION_MAJOR} in
3)
echo "LATEST_TAG=v3-latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=v3-stable" >> "${GITHUB_ENV}"
;;
4)
echo "LATEST_TAG=latest" >> "${GITHUB_ENV}"
echo "STABLE_TAG=stable" >> "${GITHUB_ENV}"
;;
*)
# Fallback if any other version is present
echo "Releasing another Prowler major version, aborting..."
exit 1
;;
esac
- name: Update Prowler version (release)
id: update-prowler-version
if: github.event_name == 'release'
run: |
poetry version ${{ github.event.release.tag_name }}
PROWLER_VERSION="${{ github.event.release.tag_name }}"
poetry version "${PROWLER_VERSION}"
echo "PROWLER_VERSION=${PROWLER_VERSION}" >> "${GITHUB_ENV}"
echo "PROWLER_VERSION=${PROWLER_VERSION}" >> "${GITHUB_OUTPUT}"
- name: Login to DockerHub
uses: docker/login-action@v3
with:
@@ -90,9 +137,9 @@ jobs:
context: .
push: true
tags: |
${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }}
${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.PROWLER_VERSION }}
${{ secrets.DOCKER_HUB_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.PROWLER_VERSION }}
${{ secrets.PUBLIC_ECR_REPOSITORY }}/${{ env.IMAGE_NAME }}:${{ env.STABLE_TAG }}
file: ${{ env.DOCKERFILE_PATH }}
cache-from: type=gha
@@ -102,16 +149,26 @@ jobs:
needs: container-build-push
runs-on: ubuntu-latest
steps:
- name: Get latest commit info
- name: Get latest commit info (latest)
if: github.event_name == 'push'
run: |
LATEST_COMMIT_HASH=$(echo ${{ github.event.after }} | cut -b -7)
echo "LATEST_COMMIT_HASH=${LATEST_COMMIT_HASH}" >> $GITHUB_ENV
- name: Dispatch event for latest
if: github.event_name == 'push'
- name: Dispatch event (latest)
if: github.event_name == 'push' && needs.container-build-push.outputs.prowler_version_major == '3'
run: |
curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" -H "X-GitHub-Api-Version: 2022-11-28" --data '{"event_type":"dispatch","client_payload":{"version":"latest", "tag": "${{ env.LATEST_COMMIT_HASH }}"}}'
- name: Dispatch event for release
if: github.event_name == 'release'
curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
--data '{"event_type":"dispatch","client_payload":{"version":"v3-latest", "tag": "${{ env.LATEST_COMMIT_HASH }}"}}'
- name: Dispatch event (release)
if: github.event_name == 'release' && needs.container-build-push.outputs.prowler_version_major == '3'
run: |
curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" -H "X-GitHub-Api-Version: 2022-11-28" --data '{"event_type":"dispatch","client_payload":{"version":"release", "tag":"${{ github.event.release.tag_name }}"}}'
curl https://api.github.com/repos/${{ secrets.DISPATCH_OWNER }}/${{ secrets.DISPATCH_REPO }}/dispatches \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
--data '{"event_type":"dispatch","client_payload":{"version":"release", "tag":"${{ needs.container-build-push.outputs.prowler_version }}"}}'
+2 -2
View File
@@ -13,10 +13,10 @@ name: "CodeQL"
on:
push:
branches: [ "master", "prowler-4.0-dev" ]
branches: [ "master", "v3" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master", "prowler-4.0-dev" ]
branches: [ "master", "v3" ]
schedule:
- cron: '00 12 * * *'
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@v3.67.6
uses: trufflesecurity/trufflehog@v3.72.0
with:
path: ./
base: ${{ github.event.repository.default_branch }}
+1 -1
View File
@@ -4,7 +4,7 @@ on:
pull_request_target:
branches:
- "master"
- "prowler-4.0-dev"
- "v3"
jobs:
labeler:
+3 -3
View File
@@ -4,11 +4,11 @@ on:
push:
branches:
- "master"
- "prowler-4.0-dev"
- "v3"
pull_request:
branches:
- "master"
- "prowler-4.0-dev"
- "v3"
jobs:
build:
runs-on: ubuntu-latest
@@ -20,7 +20,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@v42
uses: tj-actions/changed-files@v44
with:
files: ./**
files_ignore: |
+56 -29
View File
@@ -6,7 +6,10 @@ on:
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
GITHUB_BRANCH: master
PYTHON_VERSION: 3.11
CACHE: "poetry"
# TODO: create a bot user for this kind of tasks, like prowler-bot
GIT_COMMITTER_EMAIL: "sergio@prowler.com"
jobs:
release-prowler-job:
@@ -15,56 +18,80 @@ jobs:
POETRY_VIRTUALENVS_CREATE: "false"
name: Release Prowler to PyPI
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Get Prowler version
run: |
PROWLER_VERSION="${{ env.RELEASE_TAG }}"
case ${PROWLER_VERSION%%.*} in
3)
echo "Releasing Prowler v3 with tag ${PROWLER_VERSION}"
;;
4)
echo "Releasing Prowler v4 with tag ${PROWLER_VERSION}"
;;
*)
echo "Releasing another Prowler major version, aborting..."
exit 1
;;
esac
- uses: actions/checkout@v4
with:
ref: ${{ env.GITHUB_BRANCH }}
- name: Install dependencies
run: |
pipx install poetry
pipx inject poetry poetry-bumpversion
- name: setup python
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: 3.9
cache: 'poetry'
- name: Change version and Build package
python-version: ${{ env.PYTHON_VERSION }}
cache: ${{ env.CACHE }}
- name: Update Poetry and config version
run: |
poetry version ${{ env.RELEASE_TAG }}
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
- name: Push updated version to the release tag
run: |
# Configure Git
git config user.name "github-actions"
git config user.email "<noreply@github.com>"
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
# Add the files with the version changed
git add prowler/config/config.py pyproject.toml
git commit -m "chore(release): ${{ env.RELEASE_TAG }}" --no-verify
git tag -fa ${{ env.RELEASE_TAG }} -m "chore(release): ${{ env.RELEASE_TAG }}"
git commit -m "chore(release): ${{ env.RELEASE_TAG }}" --no-verify -S
# Replace the tag with the version updated
git tag -fa ${{ env.RELEASE_TAG }} -m "chore(release): ${{ env.RELEASE_TAG }}" --sign
# Push the tag
git push -f origin ${{ env.RELEASE_TAG }}
- name: Build Prowler package
run: |
poetry build
- name: Publish prowler package to PyPI
- name: Publish Prowler package to PyPI
run: |
poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
poetry publish
# Create pull request with new version
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.PROWLER_ACCESS_TOKEN }}
commit-message: "chore(release): update Prowler Version to ${{ env.RELEASE_TAG }}."
branch: release-${{ env.RELEASE_TAG }}
labels: "status/waiting-for-revision, severity/low"
title: "chore(release): update Prowler Version to ${{ env.RELEASE_TAG }}"
body: |
### Description
This PR updates Prowler Version to ${{ env.RELEASE_TAG }}.
### License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
- name: Replicate PyPi Package
- name: Replicate PyPI package
run: |
rm -rf ./dist && rm -rf ./build && rm -rf prowler.egg-info
pip install toml
python util/replicate_pypi_package.py
poetry build
- name: Publish prowler-cloud package to PyPI
run: |
poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
@@ -55,7 +55,7 @@ jobs:
token: ${{ secrets.PROWLER_ACCESS_TOKEN }}
commit-message: "feat(regions_update): Update regions for AWS services."
branch: "aws-services-regions-updated-${{ github.sha }}"
labels: "status/waiting-for-revision, severity/low, provider/aws"
labels: "status/waiting-for-revision, severity/low, provider/aws, backport-v3"
title: "chore(regions_update): Changes in regions for AWS services."
body: |
### Description
+5 -1
View File
@@ -9,8 +9,9 @@
__pycache__
venv/
build/
dist/
/dist/
*.egg-info/
*/__pycache__/*.pyc
# Session
Session.vim
@@ -51,3 +52,6 @@ junit-reports/
.coverage*
.coverage
coverage*
# Node
node_modules
+1
View File
@@ -26,6 +26,7 @@ repos:
rev: v0.9.0
hooks:
- id: shellcheck
exclude: contrib
## PYTHON
- repo: https://github.com/myint/autoflake
rev: v2.2.1
+7 -5
View File
@@ -8,16 +8,18 @@ version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3.9"
python: "3.11"
jobs:
post_create_environment:
# Install poetry
# https://python-poetry.org/docs/#installing-manually
- pip install poetry
# Tell poetry to not use a virtual environment
- poetry config virtualenvs.create false
- python -m pip install poetry
post_install:
- poetry install -E docs
# Install dependencies with 'docs' dependency group
# https://python-poetry.org/docs/managing-dependencies/#dependency-groups
# VIRTUAL_ENV needs to be set manually for now.
# See https://github.com/readthedocs/readthedocs.org/pull/11152/
- VIRTUAL_ENV=${READTHEDOCS_VIRTUALENV_PATH} python -m poetry install --only=docs
mkdocs:
configuration: mkdocs.yml
+7 -2
View File
@@ -1,4 +1,4 @@
FROM python:3.11-alpine
FROM python:3.12-alpine
LABEL maintainer="https://github.com/prowler-cloud/prowler"
@@ -15,7 +15,8 @@ USER prowler
# Copy necessary files
WORKDIR /home/prowler
COPY prowler/ /home/prowler/prowler/
COPY prowler/ /home/prowler/prowler/
COPY dashboard/ /home/prowler/dashboard/
COPY pyproject.toml /home/prowler
COPY README.md /home/prowler
@@ -26,6 +27,10 @@ ENV PATH="$HOME/.local/bin:$PATH"
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir .
# Remove deprecated dash dependencies
RUN pip uninstall dash-html-components -y && \
pip uninstall dash-core-components -y
# Remove Prowler directory and build files
USER 0
RUN rm -rf /home/prowler/prowler /home/prowler/pyproject.toml /home/prowler/README.md /home/prowler/build /home/prowler/prowler.egg-info
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Netflix, Inc.
Copyright @ 2024 Toni de la Fuente
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+1 -1
View File
@@ -27,7 +27,7 @@ lint: ## Lint Code
@echo "Running black... "
black --check .
@echo "Running pylint..."
pylint --disable=W,C,R,E -j 0 providers lib util config
pylint --disable=W,C,R,E -j 0 prowler util
##@ PyPI
pypi-clean: ## Delete the distribution files
+33 -8
View File
@@ -9,6 +9,12 @@
<b>Learn more at <a href="https://prowler.com">prowler.com</i></b>
</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/3985464/3617e470-670c-47c9-9794-ce895ebdb627"></a>
<br>
<a href="https://join.slack.com/t/prowler-workspace/shared_invite/zt-1hix76xsl-2uq222JIXrC7Q8It~9ZNog">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>
@@ -39,16 +45,16 @@
It contains hundreds of controls covering CIS, NIST 800, NIST CSF, CISA, RBI, FedRAMP, PCI-DSS, GDPR, HIPAA, FFIEC, SOC2, GXP, AWS Well-Architected Framework Security Pillar, AWS Foundational Technical Review (FTR), ENS (Spanish National Security Scheme) and your custom security frameworks.
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.cloud/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.cloud/en/latest/tutorials/misc/#categories) |
| 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 | 302 | 61 -> `prowler aws --list-services` | 27 -> `prowler aws --list-compliance` | 6 -> `prowler aws --list-categories` |
| GCP | 73 | 11 -> `prowler gcp --list-services` | 1 -> `prowler gcp --list-compliance` | 2 -> `prowler gcp --list-categories`|
| Azure | 37 | 4 -> `prowler azure --list-services` | CIS soon | 1 -> `prowler azure --list-categories` |
| Kubernetes | Work In Progress | - | CIS soon | - |
| AWS | 304 | 61 -> `prowler aws --list-services` | 28 -> `prowler aws --list-compliance` | 6 -> `prowler aws --list-categories` |
| GCP | 75 | 11 -> `prowler gcp --list-services` | 1 -> `prowler gcp --list-compliance` | 2 -> `prowler gcp --list-categories`|
| Azure | 127 | 16 -> `prowler azure --list-services` | 2 -> `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` |
# 📖 Documentation
The full documentation can now be found at [https://docs.prowler.cloud](https://docs.prowler.cloud)
The full documentation can now be found at [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/)
## Looking for Prowler v2 documentation?
For Prowler v2 Documentation, please go to https://github.com/prowler-cloud/prowler/tree/2.12.1.
@@ -62,7 +68,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
pip install prowler
prowler -v
```
More details at https://docs.prowler.cloud
More details at [https://docs.prowler.com](https://docs.prowler.com/projects/prowler-open-source/en/latest/)
## Containers
@@ -93,7 +99,7 @@ python prowler.py -v
You can run Prowler from your workstation, an EC2 instance, Fargate or any other container, Codebuild, CloudShell and Cloud9.
![Architecture](https://github.com/prowler-cloud/prowler/assets/38561120/080261d9-773d-4af1-af79-217a273e3176)
![Architecture](https://github.com/prowler-cloud/prowler/assets/38561120/710f0def-6e3e-4b3e-b8fa-4b3e7db1ed9f)
# 📝 Requirements
@@ -267,6 +273,25 @@ prowler gcp --credentials-file path
```
> By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned.
## Kubernetes
For non in-cluster execution, you can provide the location of the KubeConfig file with the following argument:
```console
prowler kubernetes --kubeconfig-file path
```
For in-cluster execution, you can use the supplied yaml to run Prowler as a job:
```console
kubectl apply -f job.yaml
kubectl apply -f prowler-role.yaml
kubectl apply -f prowler-rolebinding.yaml
kubectl get pods --> prowler-XXXXX
kubectl logs prowler-XXXXX
```
> By default, `prowler` will scan all namespaces in your active Kubernetes context, use flag `--context` to specify the context to be scanned and `--namespaces` to specify the namespaces to be scanned.
# 📃 License
Prowler is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at
+6 -15
View File
@@ -1,17 +1,8 @@
#!/bin/bash
# Install system dependencies
sudo yum -y install openssl-devel bzip2-devel libffi-devel gcc
# Upgrade to Python 3.9
cd /tmp && wget https://www.python.org/ftp/python/3.9.13/Python-3.9.13.tgz
tar zxf Python-3.9.13.tgz
cd Python-3.9.13/ || exit
./configure --enable-optimizations
sudo make altinstall
python3.9 --version
# Install Prowler
cd ~ || exit
python3.9 -m pip install prowler-cloud
prowler -v
# Run Prowler
prowler
sudo bash
adduser prowler
su prowler
pip install prowler
cd /tmp || exit
prowler aws
+176
View File
@@ -0,0 +1,176 @@
# Importing Packages
import sys
import warnings
import click
import dash
import dash_bootstrap_components as dbc
from colorama import Fore, Style
from dash import dcc, html
from dash.dependencies import Input, Output
from dashboard.config import folder_path_overview
from prowler.config.config import orange_color
from prowler.lib.banner import print_banner
warnings.filterwarnings("ignore")
cli = sys.modules["flask.cli"]
print_banner(verbose=False)
print(
f"{Fore.GREEN}Loading all CSV files from the folder {folder_path_overview} ...\n{Style.RESET_ALL}"
)
cli.show_server_banner = lambda *x: click.echo(
f"{Fore.YELLOW}NOTE:{Style.RESET_ALL} If you are a {Fore.GREEN}{Style.BRIGHT}Prowler SaaS{Style.RESET_ALL} customer and you want to use your data from your S3 bucket,\nrun: `{orange_color}aws s3 cp s3://<your-bucket>/output/csv ./output --recursive{Style.RESET_ALL}`\nand then run `prowler dashboard` again to load the new files."
)
# Initialize the app - incorporate css
dashboard = dash.Dash(
__name__,
external_stylesheets=[dbc.themes.DARKLY],
use_pages=True,
suppress_callback_exceptions=True,
title="Prowler Dashboard",
)
# Logo
prowler_logo = html.Img(
src="https://prowler.com/wp-content/uploads/logo-dashboard.png", alt="Prowler Logo"
)
menu_icons = {
"overview": "/assets/images/icons/overview.svg",
"compliance": "/assets/images/icons/compliance.svg",
}
# Function to generate navigation links
def generate_nav_links(current_path):
nav_links = []
for page in dash.page_registry.values():
# Gets the icon URL based on the page name
icon_url = menu_icons.get(page["name"].lower())
is_active = (
" bg-prowler-stone-950 border-r-4 border-solid border-prowler-lime"
if current_path == page["relative_path"]
else ""
)
link_class = f"block hover:bg-prowler-stone-950 hover:border-r-4 hover:border-solid hover:border-prowler-lime{is_active}"
link_content = html.Span(
[
html.Img(src=icon_url, className="w-5"),
html.Span(page["name"], className="font-medium text-base leading-6"),
],
className="flex justify-center lg:justify-normal items-center gap-x-3 py-2 px-3",
)
nav_link = html.Li(
dcc.Link(link_content, href=page["relative_path"], className=link_class)
)
nav_links.append(nav_link)
return nav_links
def generate_help_menu():
help_links = [
{
"title": "Help",
"url": "https://github.com/prowler-cloud/prowler/issues",
"icon": "/assets/images/icons/help.png",
},
{
"title": "Docs",
"url": "https://docs.prowler.com",
"icon": "/assets/images/icons/docs.png",
},
]
link_class = "block hover:bg-prowler-stone-950 hover:border-r-4 hover:border-solid hover:border-prowler-lime"
menu_items = []
for link in help_links:
menu_item = html.Li(
html.A(
html.Span(
[
html.Img(src=link["icon"], className="w-5"),
html.Span(
link["title"], className="font-medium text-base leading-6"
),
],
className="flex items-center gap-x-3 py-2 px-3",
),
href=link["url"],
target="_blank",
className=link_class,
)
)
menu_items.append(menu_item)
return menu_items
# Layout
dashboard.layout = html.Div(
[
dcc.Location(id="url", refresh=False),
html.Link(rel="icon", href="assets/favicon.ico"),
# Placeholder for dynamic navigation bar
html.Div(
[
html.Div(
id="navigation-bar", className="bg-prowler-stone-900 min-w-36 z-10"
),
html.Div(
[
dash.page_container,
],
id="content_select",
className="bg-prowler-white w-full col-span-11 h-screen mx-auto overflow-y-scroll no-scrollbar px-10 py-7",
),
],
className="grid custom-grid 2xl:custom-grid-large h-screen",
),
],
className="h-screen mx-auto",
)
# Callback to update navigation bar
@dashboard.callback(Output("navigation-bar", "children"), [Input("url", "pathname")])
def update_nav_bar(pathname):
return html.Div(
[
html.Div([prowler_logo], className="mb-8 px-3"),
html.H6(
"Dashboards",
className="px-3 text-prowler-stone-500 text-sm opacity-90 font-regular mb-2",
),
html.Nav(
[html.Ul(generate_nav_links(pathname), className="")],
className="flex flex-col gap-y-6",
),
html.Nav(
[
html.A(
[
html.Span(
[
html.Img(src="assets/favicon.ico", className="w-5"),
"Subscribe to prowler SaaS",
],
className="flex items-center gap-x-3",
),
],
href="https://prowler.com/",
target="_blank",
className="block p-3 uppercase text-xs hover:bg-prowler-stone-950 hover:border-r-4 hover:border-solid hover:border-prowler-lime",
),
html.Ul(generate_help_menu(), className=""),
],
className="flex flex-col gap-y-6 mt-auto",
),
],
className="flex flex-col bg-prowler-stone-900 py-7 h-full",
)
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#FFF" aria-hidden="true" class="h-5 w-5" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M9 1.5H5.625c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5zm6.61 10.936a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 14.47a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25z" clip-rule="evenodd"/>
<path d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963z"/>
</svg>

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#FFF" aria-hidden="true" class="h-5 w-5" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M2.25 13.5a8.25 8.25 0 0 1 8.25-8.25.75.75 0 0 1 .75.75v6.75H18a.75.75 0 0 1 .75.75 8.25 8.25 0 0 1-16.5 0z" clip-rule="evenodd"/>
<path fill-rule="evenodd" d="M12.75 3a.75.75 0 0 1 .75-.75 8.25 8.25 0 0 1 8.25 8.25.75.75 0 0 1-.75.75h-7.5a.75.75 0 0 1-.75-.75V3z" clip-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format2
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format2(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format1
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format1(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format1
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format1(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,22 @@
import warnings
from dashboard.common_methods import get_section_containers_format2
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ATTRIBUTES_NAME",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_format2(
aux, "REQUIREMENTS_ATTRIBUTES_NAME", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format2
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ATTRIBUTES_NAME",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_format2(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ATTRIBUTES_NAME"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+23
View File
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format1
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format1(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+29
View File
@@ -0,0 +1,29 @@
import warnings
from dashboard.common_methods import get_section_containers_ens
warnings.filterwarnings("ignore")
def get_table(data):
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",
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+23
View File
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format1
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format1(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format1
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format1(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+23
View File
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_container_iso
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ATTRIBUTES_CATEGORY",
"REQUIREMENTS_ATTRIBUTES_OBJETIVE_ID",
"REQUIREMENTS_ATTRIBUTES_OBJETIVE_NAME",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_container_iso(
aux, "REQUIREMENTS_ATTRIBUTES_CATEGORY", "REQUIREMENTS_ATTRIBUTES_OBJETIVE_ID"
)
+23
View File
@@ -0,0 +1,23 @@
import warnings
from dashboard.common_methods import get_section_containers_format2
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_SUBTECHNIQUES",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format2(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_SUBTECHNIQUES"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+20
View File
@@ -0,0 +1,20 @@
import warnings
from dashboard.common_methods import get_section_containers_pci
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_pci(aux, "REQUIREMENTS_ID")
@@ -0,0 +1,20 @@
import warnings
from dashboard.common_methods import get_section_containers_rbi
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
]
return get_section_containers_rbi(aux, "REQUIREMENTS_ID")
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_format3
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_format3(
aux, "REQUIREMENTS_ATTRIBUTES_SECTION", "REQUIREMENTS_ID"
)
+29
View File
@@ -0,0 +1,29 @@
import os
# Emojis to be used in the compliance table
pass_emoji = ""
fail_emoji = ""
info_emoji = ""
manual_emoji = "✋🏽"
# Main colors
fail_color = "#e67272"
pass_color = "#54d283"
info_color = "#2684FF"
manual_color = "#636c78"
# Muted colors
muted_fail_color = "#fca903"
muted_pass_color = "#03fccf"
muted_manual_color = "#b33696"
# Severity colors
critical_color = "#951649"
high_color = "#e11d48"
medium_color = "#ee6f15"
low_color = "#f9f5e6"
informational_color = "#3274d9"
# Folder output path
folder_path_overview = os.getcwd() + "/output"
folder_path_compliance = os.getcwd() + "/output/compliance"
+157
View File
@@ -0,0 +1,157 @@
from typing import List
from dash import html
def create_provider_card(
provider: str, provider_logo: str, account_type: str, filtered_data
) -> List[html.Div]:
"""
Card to display the provider's name and icon.
Args:
provider (str): Name of the provider.
provider_icon (str): Icon of the provider.
Returns:
html.Div: Card to display the provider's name and icon.
"""
accounts = len(
filtered_data[filtered_data["PROVIDER"] == provider]["ACCOUNT_UID"].unique()
)
checks_executed = len(
filtered_data[filtered_data["PROVIDER"] == provider]["CHECK_ID"].unique()
)
fails = len(
filtered_data[
(filtered_data["PROVIDER"] == provider)
& (filtered_data["STATUS"] == "FAIL")
]
)
passes = len(
filtered_data[
(filtered_data["PROVIDER"] == provider)
& (filtered_data["STATUS"] == "PASS")
]
)
# Take the values in the MUTED colum that are true for the provider
if "MUTED" in filtered_data.columns:
muted = len(
filtered_data[
(filtered_data["PROVIDER"] == provider)
& (filtered_data["MUTED"] == "True")
]
)
else:
muted = 0
return [
html.Div(
[
html.Div(
[
html.Div(
[
html.Div(
[
html.Div([provider_logo], className="w-8"),
],
className="p-2 shadow-box-up rounded-full",
),
html.H5(
f"{provider.upper()} {account_type}",
className="text-base font-semibold leading-snug tracking-normal text-gray-900",
),
],
className="flex justify-between items-center mb-3",
),
html.Div(
[
html.Div(
[
html.Span(
account_type,
className="text-prowler-stone-900 inline-block text-3xs font-bold uppercase transition-all rounded-lg text-prowler-stone-900 shadow-box-up px-4 py-1 text-center col-span-6 flex justify-center items-center",
),
html.Div(
accounts,
className="inline-block text-xs text-prowler-stone-900 font-bold shadow-box-down px-4 py-1 rounded-lg text-center col-span-5 col-end-13",
),
],
className="grid grid-cols-12",
),
html.Div(
[
html.Span(
"Checks",
className="text-prowler-stone-900 inline-block text-3xs font-bold uppercase transition-all rounded-lg text-prowler-stone-900 shadow-box-up px-4 py-1 text-center col-span-6 flex justify-center items-center",
),
html.Div(
checks_executed,
className="inline-block text-xs text-prowler-stone-900 font-bold shadow-box-down px-4 py-1 rounded-lg text-center col-span-5 col-end-13",
),
],
className="grid grid-cols-12",
),
html.Div(
[
html.Span(
"FAILED",
className="text-prowler-stone-900 inline-block text-3xs font-bold uppercase transition-all rounded-lg text-prowler-stone-900 shadow-box-up px-4 py-1 text-center col-span-6 flex justify-center items-center",
),
html.Div(
[
html.Div(
fails,
className="m-[2px] px-4 py-1 rounded-lg bg-gradient-failed",
),
],
className="inline-block text-xs font-bold shadow-box-down rounded-lg text-center col-span-5 col-end-13",
),
],
className="grid grid-cols-12",
),
html.Div(
[
html.Span(
"PASSED",
className="text-prowler-stone-900 inline-block text-3xs font-bold uppercase transition-all rounded-lg text-prowler-stone-900 shadow-box-up px-4 py-1 text-center col-span-6 flex justify-center items-center",
),
html.Div(
[
html.Div(
passes,
className="m-[2px] px-4 py-1 rounded-lg bg-gradient-passed",
),
],
className="inline-block text-xs font-bold shadow-box-down rounded-lg text-center col-span-5 col-end-13",
),
],
className="grid grid-cols-12",
),
html.Div(
[
html.Span(
"MUTED",
className="text-prowler-stone-900 inline-block text-3xs font-bold uppercase transition-all rounded-lg text-prowler-stone-900 shadow-box-up px-4 py-1 text-center col-span-6 flex justify-center items-center",
),
html.Div(
[
html.Div(
muted,
className="m-[2px] px-4 py-1 rounded-lg bg-gradient-muted",
),
],
className="inline-block text-xs font-bold shadow-box-down rounded-lg text-center col-span-5 col-end-13",
),
],
className="grid grid-cols-12",
),
],
className="grid gap-x-8 gap-y-4",
),
],
className="px-4 py-3",
),
],
className="relative flex flex-col bg-white shadow-provider rounded-xl w-full transition ease-in-out delay-100 hover:-translate-y-1 hover:scale-110 hover:z-50 hover:cursor-pointer",
)
]
+289
View File
@@ -0,0 +1,289 @@
from dash import dcc, html
def create_date_dropdown(assesment_times: list) -> html.Div:
"""
Dropdown to select the date of the last available scan for each account.
Args:
assesment_times (list): List of dates of the last available scan for each account.
Returns:
html.Div: Dropdown to select the date of the last available scan for each account.
"""
return html.Div(
[
html.Div(
[
html.Label(
"Assessment date (last available scan) ",
className="text-prowler-stone-900 font-bold text-sm",
),
html.Img(
id="info-file-over",
src="/assets/images/icons/help-black.png",
className="w-5",
title="The date of the last available scan for each account is displayed here. If you have not run prowler yet, the date will be empty.",
),
],
style={"display": "inline-flex"},
),
dcc.Dropdown(
id="report-date-filter",
options=[
{"label": account, "value": account} for account in assesment_times
],
value=assesment_times[0],
clearable=False,
multi=False,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_date_dropdown_compliance(assesment_times: list) -> html.Div:
"""
Dropdown to select the date of the last available scan for each account.
Args:
assesment_times (list): List of dates of the last available scan for each account.
Returns:
html.Div: Dropdown to select the date of the last available scan for each account.
"""
return html.Div(
[
html.Label(
"Assesment Date:", className="text-prowler-stone-900 font-bold text-sm"
),
dcc.Dropdown(
id="date-filter-analytics",
options=[
{"label": account, "value": account} for account in assesment_times
],
value=assesment_times[0],
clearable=False,
multi=False,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_region_dropdown(regions: list) -> html.Div:
"""
Dropdown to select the region of the account.
Args:
regions (list): List of regions of the account.
Returns:
html.Div: Dropdown to select the region of the account.
"""
return html.Div(
[
html.Label(
"Region / Location / Namespace :",
className="text-prowler-stone-900 font-bold text-sm",
),
dcc.Dropdown(
id="region-filter",
options=[{"label": region, "value": region} for region in regions],
value=["All"], # Initial selection is ALL
clearable=False,
multi=True,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_region_dropdown_compliance(regions: list) -> html.Div:
"""
Dropdown to select the region of the account.
Args:
regions (list): List of regions of the account.
Returns:
html.Div: Dropdown to select the region of the account.
"""
return html.Div(
[
html.Label(
"Region / Location / Namespace :",
className="text-prowler-stone-900 font-bold text-sm",
),
dcc.Dropdown(
id="region-filter-compliance",
options=[{"label": region, "value": region} for region in regions],
value=["All"], # Initial selection is ALL
clearable=False,
multi=True,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_account_dropdown(accounts: list) -> html.Div:
"""
Dropdown to select the account.
Args:
accounts (list): List of accounts.
Returns:
html.Div: Dropdown to select the account.
"""
return html.Div(
[
html.Label(
"Account / Subscription / Project / Cluster :",
className="text-prowler-stone-900 font-bold text-sm",
),
dcc.Dropdown(
id="cloud-account-filter",
options=[{"label": account, "value": account} for account in accounts],
value=["All"], # Initial selection is ALL
clearable=False,
multi=True,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_account_dropdown_compliance(accounts: list) -> html.Div:
"""
Dropdown to select the account.
Args:
accounts (list): List of accounts.
Returns:
html.Div: Dropdown to select the account.
"""
return html.Div(
[
html.Label(
"Account / Subscription / Project / Cluster :",
className="text-prowler-stone-900 font-bold text-sm",
),
dcc.Dropdown(
id="cloud-account-filter-compliance",
options=[{"label": account, "value": account} for account in accounts],
value=["All"], # Initial selection is ALL
clearable=False,
multi=True,
style={"color": "#000000", "width": "100%"},
),
],
)
def create_compliance_dropdown(compliance: list) -> html.Div:
"""
Dropdown to select the compliance.
Args:
compliance (list): List of compliance.
Returns:
html.Div: Dropdown to select the compliance.
"""
return html.Div(
[
html.Label(
"Compliance:", className="text-prowler-stone-900 font-bold text-sm"
),
dcc.Dropdown(
id="report-compliance-filter",
options=[{"label": i, "value": i} for i in compliance],
value=compliance[0],
clearable=False,
style={"color": "#000000"},
),
],
)
def create_severity_dropdown(severity: list) -> html.Div:
"""
Dropdown to select the severity.
Args:
severity (list): List of severity.
Returns:
html.Div: Dropdown to select the severity.
"""
return html.Div(
[
html.Label(
"Severity:", className="text-prowler-stone-900 font-bold text-sm"
),
dcc.Dropdown(
id="severity-filter",
options=[{"label": i, "value": i} for i in severity],
value=["All"],
clearable=False,
multi=True,
style={"color": "#000000"},
),
],
)
def create_service_dropdown(services: list) -> html.Div:
"""
Dropdown to select the service.
Args:
services (list): List of services.
Returns:
html.Div: Dropdown to select the service.
"""
return html.Div(
[
html.Label(
"Service:", className="text-prowler-stone-900 font-bold text-sm"
),
dcc.Dropdown(
id="service-filter",
options=[{"label": i, "value": i} for i in services],
value=["All"],
clearable=False,
multi=True,
style={"color": "#000000"},
),
],
)
def create_status_dropdown(status: list) -> html.Div:
"""
Dropdown to select the status.
Args:
status (list): List of status.
Returns:
html.Div: Dropdown to select the status.
"""
return html.Div(
[
html.Label("Status:", className="text-prowler-stone-900 font-bold text-sm"),
dcc.Dropdown(
id="status-filter",
options=[{"label": i, "value": i} for i in status],
value=["All"],
clearable=False,
multi=True,
style={"color": "#000000"},
),
],
)
def create_table_row_dropdown(table_rows: list) -> html.Div:
"""
Dropdown to select the number of rows in the table.
Args:
table_rows (list): List of number of rows.
Returns:
html.Div: Dropdown to select the number of rows in the table.
"""
return html.Div(
[
dcc.Dropdown(
id="table-rows",
options=[{"label": i, "value": i} for i in table_rows],
value=table_rows[0],
clearable=False,
style={"color": "#000000", "margin-right": "10px"},
),
],
)
+172
View File
@@ -0,0 +1,172 @@
from dash import dcc, html
def create_layout_overview(
account_dropdown: html.Div,
date_dropdown: html.Div,
region_dropdown: html.Div,
download_button: html.Button,
severity_dropdown: html.Div,
service_dropdown: html.Div,
table_row_dropdown: html.Div,
status_dropdown: html.Div,
) -> html.Div:
"""
Create the layout of the dashboard.
Args:
account_dropdown (html.Div): Dropdown to select the account.
date_dropdown (html.Div): Dropdown to select the date of the last available scan for each account.
region_dropdown (html.Div): Dropdown to select the region of the account.
Returns:
html.Div: Layout of the dashboard.
"""
return html.Div(
[
dcc.Location(id="url", refresh=False),
html.Div(
[
html.H1(
"Scan Overview",
className="text-prowler-stone-900 text-2xxl font-bold",
),
html.Div(className="d-flex flex-wrap", id="subscribe_card"),
],
className="flex justify-between border-b border-prowler-500 pb-3",
),
html.Div(
[
html.Div([date_dropdown], className=""),
html.Div([account_dropdown], className=""),
html.Div([region_dropdown], className=""),
],
className="grid gap-x-4 gap-y-4 sm:grid-cols-2 lg:grid-cols-3 lg:gap-y-0",
),
html.Div(
[
html.Div([severity_dropdown], className=""),
html.Div([service_dropdown], className=""),
html.Div([status_dropdown], className=""),
],
className="grid gap-x-4 gap-y-4 sm:grid-cols-2 lg:grid-cols-3 lg:gap-y-0",
),
html.Div(
[
html.Div(className="flex", id="aws_card", n_clicks=0),
html.Div(className="flex", id="azure_card", n_clicks=0),
html.Div(className="flex", id="gcp_card", n_clicks=0),
html.Div(className="flex", id="k8s_card", n_clicks=0),
],
className="grid gap-x-4 gap-y-4 sm:grid-cols-2 lg:grid-cols-4 lg:gap-y-0",
),
html.H4(
"Count of Findings by severity",
className="text-prowler-stone-900 text-lg font-bold",
),
html.Div(
[
html.Div(
className="flex flex-col col-span-12 sm:col-span-6 lg:col-span-3 gap-y-4",
id="status_graph",
),
html.Div(
className="flex flex-col col-span-12 sm:col-span-6 lg:col-span-3 gap-y-4",
id="two_pie_chart",
),
html.Div(
className="flex flex-col col-span-12 sm:col-span-6 lg:col-span-6 col-end-13 gap-y-4",
id="line_plot",
),
],
className="grid gap-x-4 gap-y-4 grid-cols-12 lg:gap-y-0",
),
html.Div(
[
html.H4(
"Top Findings by Severity",
className="text-prowler-stone-900 text-lg font-bold",
),
html.Div(
[
(
html.Label(
"Table Rows:",
className="text-prowler-stone-900 font-bold text-sm",
style={"margin-right": "10px"},
)
),
table_row_dropdown,
download_button,
],
className="flex justify-between items-center",
),
dcc.Download(id="download-data"),
],
className="flex justify-between items-center",
),
html.Div(id="table", className="grid"),
],
className="grid gap-x-8 gap-y-8 2xl:container mx-auto",
)
def create_layout_compliance(
account_dropdown: html.Div,
date_dropdown: html.Div,
region_dropdown: html.Div,
compliance_dropdown: html.Div,
) -> html.Div:
return html.Div(
[
dcc.Location(id="url", refresh=False),
html.Div(
[
html.H1(
"Compliance",
className="text-prowler-stone-900 text-2xxl font-bold",
),
html.A(
[
html.Img(src="assets/favicon.ico", className="w-5 mr-3"),
html.Span("Subscribe to prowler SaaS"),
],
href="https://prowler.pro/",
target="_blank",
className="text-prowler-stone-900 inline-flex px-4 py-2 text-xs font-bold uppercase transition-all rounded-lg text-gray-900 hover:bg-prowler-stone-900/10 border-solid border-1 hover:border-prowler-stone-900/10 hover:border-solid hover:border-1 border-prowler-stone-900/10",
),
],
className="flex justify-between border-b border-prowler-500 pb-3",
),
html.Div(
[
html.Div([date_dropdown], className=""),
html.Div([account_dropdown], className=""),
html.Div([region_dropdown], className=""),
html.Div([compliance_dropdown], className=""),
],
className="grid gap-x-4 gap-y-4 sm:grid-cols-2 lg:grid-cols-4 lg:gap-y-0",
),
html.Div(
[
html.Div(
className="flex flex-col col-span-12 md:col-span-4 gap-y-4",
id="overall_status_result_graph",
),
html.Div(
className="flex flex-col col-span-12 md:col-span-7 md:col-end-13 gap-y-4",
id="security_level_graph",
),
html.Div(
className="flex flex-col col-span-12 md:col-span-2 gap-y-4",
id="",
),
],
className="grid gap-x-4 gap-y-4 grid-cols-12 lg:gap-y-0",
),
html.H4(
"Details compliance:",
className="text-prowler-stone-900 text-lg font-bold",
),
html.Div(className="flex flex-wrap", id="output"),
],
className="grid gap-x-8 gap-y-8 2xl:container mx-auto",
)
+592
View File
@@ -0,0 +1,592 @@
# Standard library imports
import csv
import glob
import importlib
import os
import re
import warnings
# Third-party imports
import dash
import pandas as pd
import plotly.express as px
from dash import callback, dcc, html
from dash.dependencies import Input, Output
# Config import
from dashboard.config import (
fail_color,
folder_path_compliance,
info_color,
manual_color,
pass_color,
)
from dashboard.lib.dropdowns import (
create_account_dropdown_compliance,
create_compliance_dropdown,
create_date_dropdown_compliance,
create_region_dropdown_compliance,
)
from dashboard.lib.layouts import create_layout_compliance
# Suppress warnings
warnings.filterwarnings("ignore")
# Global variables
# TODO: Create a flag to let the user put a custom path
csv_files = []
for file in glob.glob(os.path.join(folder_path_compliance, "*.csv")):
with open(file, "r", newline="") as csvfile:
reader = csv.reader(csvfile)
num_rows = sum(1 for row in reader)
if num_rows > 1:
csv_files.append(file)
def load_csv_files(csv_files):
# Load CSV files into a single pandas DataFrame.
dfs = []
results = []
for file in csv_files:
df = pd.read_csv(file, sep=";", on_bad_lines="skip")
if "CHECKID" in df.columns:
dfs.append(df)
result = file
result = result.split("/")[-1]
result = re.sub(r"^.*?_", "", result)
result = result.replace(".csv", "")
result = result.upper()
if "AWS" in result:
if "AWS_" in result:
result = result.replace("_AWS", "")
else:
result = result.replace("_AWS", " - AWS")
if "GCP" in result:
result = result.replace("_GCP", " - GCP")
if "AZURE" in result:
result = result.replace("_AZURE", " - AZURE")
if "KUBERNETES" in result:
result = result.replace("_KUBERNETES", " - KUBERNETES")
result = result[result.find("CIS_") :]
results.append(result)
unique_results = set(results)
results = list(unique_results)
# Check if there is any CIS report in the list and divide it in level 1 and level 2
new_results = []
old_results = results.copy()
for compliance_name in results:
if "CIS_" in compliance_name:
old_results.remove(compliance_name)
new_results.append(compliance_name + " - Level_1")
new_results.append(compliance_name + " - Level_2")
results = old_results + new_results
results.sort()
# Handle the case where there are no CSV files
try:
data = pd.concat(dfs, ignore_index=True)
except ValueError:
data = None
return data, results
data, results = load_csv_files(csv_files)
if data is None:
dash.register_page(__name__)
layout = html.Div(
[
html.Div(
[
html.H5(
"No data found, check if the CSV files are in the correct folder.",
className="card-title",
style={"text-align": "left"},
)
],
style={
"width": "99%",
"margin-right": "0.8%",
"margin-bottom": "10px",
},
)
]
)
else:
data["ASSESSMENTDATE"] = pd.to_datetime(data["ASSESSMENTDATE"])
data["ASSESSMENT_TIME"] = data["ASSESSMENTDATE"].dt.strftime("%Y-%m-%d %H:%M:%S")
data_values = data["ASSESSMENT_TIME"].unique()
data_values.sort()
data_values = data_values[::-1]
aux = []
for value in data_values:
if value.split(" ")[0] not in [aux[i].split(" ")[0] for i in range(len(aux))]:
aux.append(value)
data_values = aux
data = data[data["ASSESSMENT_TIME"].isin(data_values)]
data["ASSESSMENT_TIME"] = data["ASSESSMENT_TIME"].apply(lambda x: x.split(" ")[0])
# Select Compliance - Dropdown
compliance_dropdown = create_compliance_dropdown(results)
# Select Account - Dropdown
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:
select_account_dropdown_list = select_account_dropdown_list + list(
data["ACCOUNTID"].unique()
)
if "PROJECTID" in data.columns:
select_account_dropdown_list = select_account_dropdown_list + list(
data["PROJECTID"].unique()
)
if "SUBSCRIPTIONID" in data.columns:
select_account_dropdown_list = select_account_dropdown_list + list(
data["SUBSCRIPTIONID"].unique()
)
if "SUBSCRIPTION" in data.columns:
select_account_dropdown_list = select_account_dropdown_list + list(
data["SUBSCRIPTION"].unique()
)
list_items = []
for item in select_account_dropdown_list:
if item.__class__.__name__ == "str" and "nan" not in item:
list_items.append(item)
account_dropdown = create_account_dropdown_compliance(list_items)
# Select Region - Dropdown
select_region_dropdown_list = ["All"]
# Append to the list the unique values of the column REGION or LOCATION if it exists
if "REGION" in data.columns:
# Handle the case where the column REGION is empty
data["REGION"] = data["REGION"].fillna("-")
select_region_dropdown_list = select_region_dropdown_list + list(
data["REGION"].unique()
)
if "LOCATION" in data.columns:
# Handle the case where the column LOCATION is empty
data["LOCATION"] = data["LOCATION"].fillna("-")
select_region_dropdown_list = select_region_dropdown_list + list(
data["LOCATION"].unique()
)
# Clear the list from None and NaN values
list_items = []
for item in select_region_dropdown_list:
if item.__class__.__name__ == "str":
list_items.append(item)
region_dropdown = create_region_dropdown_compliance(list_items)
# Select Date - Dropdown
date_dropdown = create_date_dropdown_compliance(
list(data["ASSESSMENT_TIME"].unique())
)
dash.register_page(__name__)
layout = create_layout_compliance(
account_dropdown, date_dropdown, region_dropdown, compliance_dropdown
)
@callback(
[
Output("output", "children"),
Output("overall_status_result_graph", "children"),
Output("security_level_graph", "children"),
Output("cloud-account-filter-compliance", "value"),
Output("cloud-account-filter-compliance", "options"),
Output("region-filter-compliance", "value"),
Output("region-filter-compliance", "options"),
Output("date-filter-analytics", "value"),
Output("date-filter-analytics", "options"),
],
Input("report-compliance-filter", "value"),
Input("cloud-account-filter-compliance", "value"),
Input("region-filter-compliance", "value"),
Input("date-filter-analytics", "value"),
)
def display_data(
analytics_input, account_filter, region_filter_analytics, date_filter_analytics
):
current_compliance = analytics_input
analytics_input = analytics_input.replace(" - ", "_")
analytics_input = analytics_input.lower()
# Check if the compliance selected is the level 1 or level 2 of the CIS
is_level_1 = "level_1" in analytics_input
analytics_input = analytics_input.replace("_level_1", "").replace("_level_2", "")
# Filter the data based on the compliance selected
files = [file for file in csv_files if analytics_input in file]
def load_csv_files(files):
"""Load CSV files into a single pandas DataFrame."""
dfs = []
for file in files:
df = pd.read_csv(file, sep=";", on_bad_lines="skip")
dfs.append(df.astype(str))
return pd.concat(dfs, ignore_index=True)
data = load_csv_files(files)
# Rename the column LOCATION to REGION for GCP or Azure
if "gcp" in analytics_input or "azure" in analytics_input:
data = data.rename(columns={"LOCATION": "REGION"})
# Add the column ACCOUNTID to the data if the provider is kubernetes
if "kubernetes" in analytics_input:
data.rename(columns={"CONTEXT": "ACCOUNTID"}, inplace=True)
data.rename(columns={"NAMESPACE": "REGION"}, inplace=True)
if "REQUIREMENTS_ATTRIBUTES_PROFILE" in data.columns:
data["REQUIREMENTS_ATTRIBUTES_PROFILE"] = data[
"REQUIREMENTS_ATTRIBUTES_PROFILE"
].apply(lambda x: x.split(" - ")[0])
# Filter the chosen level of the CIS
if is_level_1:
data = data[data["REQUIREMENTS_ATTRIBUTES_PROFILE"] == "Level 1"]
# Rename the column PROJECTID to ACCOUNTID for GCP
if data.columns.str.contains("PROJECTID").any():
data.rename(columns={"PROJECTID": "ACCOUNTID"}, inplace=True)
# Rename the column SUBSCRIPTIONID to ACCOUNTID for Azure
if data.columns.str.contains("SUBSCRIPTIONID").any():
data.rename(columns={"SUBSCRIPTIONID": "ACCOUNTID"}, inplace=True)
# Handle v3 azure cis compliance
if data.columns.str.contains("SUBSCRIPTION").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")
updated_cloud_account_values = account_filter
elif len(account_filter) == 0:
updated_cloud_account_values = data["ACCOUNTID"].unique()
account_filter = ["All"]
else:
updated_cloud_account_values = account_filter
data = data[data["ACCOUNTID"].isin(updated_cloud_account_values)]
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)
# Filter REGION
if region_filter_analytics == ["All"]:
updated_region_account_values = data["REGION"].unique()
elif "All" in region_filter_analytics and len(region_filter_analytics) > 1:
# Remove 'All' from the list
region_filter_analytics.remove("All")
updated_region_account_values = region_filter_analytics
elif len(region_filter_analytics) == 0:
updated_region_account_values = data["REGION"].unique()
region_filter_analytics = ["All"]
else:
updated_region_account_values = region_filter_analytics
data = data[data["REGION"].isin(updated_region_account_values)]
region_filter_options = list(data["REGION"].unique())
region_filter_options = region_filter_options + ["All"]
for item in region_filter_options:
if item == "nan" or item.__class__.__name__ != "str":
region_filter_options.remove(item)
data["ASSESSMENTDATE"] = pd.to_datetime(data["ASSESSMENTDATE"], errors="coerce")
data["ASSESSMENTDATE"] = data["ASSESSMENTDATE"].dt.strftime("%Y-%m-%d %H:%M:%S")
# Choosing the date that is the most recent
data_values = data["ASSESSMENTDATE"].unique()
data_values.sort()
data_values = data_values[::-1]
aux = []
data_values = [str(i) for i in data_values]
for value in data_values:
if value.split(" ")[0] not in [aux[i].split(" ")[0] for i in range(len(aux))]:
aux.append(value)
data_values = [str(i) for i in aux]
data = data[data["ASSESSMENTDATE"].isin(data_values)]
data["ASSESSMENTDATE"] = data["ASSESSMENTDATE"].apply(lambda x: x.split(" ")[0])
options_date = data["ASSESSMENTDATE"].unique()
options_date.sort()
options_date = options_date[::-1]
# Filter DATE
if date_filter_analytics in options_date:
data = data[data["ASSESSMENTDATE"] == date_filter_analytics]
else:
date_filter_analytics = options_date[0]
data = data[data["ASSESSMENTDATE"] == date_filter_analytics]
if data.empty:
fig = px.pie()
pie_1 = dcc.Graph(
figure=fig,
config={"displayModeBar": False},
style={"height": "250px", "width": "250px", "right": "0px"},
)
return [
html.Div(
[
html.H5(
"No data found for this compliance",
className="card-title",
style={"text-align": "left"},
)
],
style={
"width": "99%",
"margin-right": "0.8%",
"margin-bottom": "10px",
},
)
]
else:
# Check cases where the compliance start with AWS_
if "aws_" in analytics_input:
analytics_input = analytics_input + "_aws"
try:
current = analytics_input.replace(".", "_")
compliance_module = importlib.import_module(
f"dashboard.compliance.{current}"
)
data.drop_duplicates(keep="first", inplace=True)
table = compliance_module.get_table(data)
except ModuleNotFoundError:
table = html.Div(
[
html.H5(
"No data found for this compliance",
className="card-title",
style={"text-align": "left", "color": "black"},
)
],
style={
"width": "99%",
"margin-right": "0.8%",
"margin-bottom": "10px",
},
)
df = data.copy()
df = df.groupby(["STATUS"]).size().reset_index(name="counts")
df = df.sort_values(by=["counts"], ascending=False)
# Pie 1
pie_1 = get_pie(df)
# Get the pie2 depending on the compliance
df = data.copy()
current_filter = ""
if "pci" in analytics_input:
pie_2 = get_bar_graph(df, "REQUIREMENTS_ID")
current_filter = "req_id"
elif (
"REQUIREMENTS_ATTRIBUTES_SECTION" in df.columns
and not df["REQUIREMENTS_ATTRIBUTES_SECTION"].isnull().values.any()
):
pie_2 = get_bar_graph(df, "REQUIREMENTS_ATTRIBUTES_SECTION")
current_filter = "sections"
elif (
"REQUIREMENTS_ATTRIBUTES_CATEGORIA" in df.columns
and not df["REQUIREMENTS_ATTRIBUTES_CATEGORIA"].isnull().values.any()
):
pie_2 = get_bar_graph(df, "REQUIREMENTS_ATTRIBUTES_CATEGORIA")
current_filter = "categorias"
elif (
"REQUIREMENTS_ATTRIBUTES_CATEGORY" in df.columns
and not df["REQUIREMENTS_ATTRIBUTES_CATEGORY"].isnull().values.any()
):
pie_2 = get_bar_graph(df, "REQUIREMENTS_ATTRIBUTES_CATEGORY")
current_filter = "categories"
elif (
"REQUIREMENTS_ATTRIBUTES_SERVICE" in df.columns
and not df["REQUIREMENTS_ATTRIBUTES_SERVICE"].isnull().values.any()
):
pie_2 = get_bar_graph(df, "REQUIREMENTS_ATTRIBUTES_SERVICE")
current_filter = "services"
else:
fig = px.pie()
fig.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=True,
showlegend=False,
paper_bgcolor="#303030",
)
pie_2 = dcc.Graph(
figure=fig,
config={"displayModeBar": False},
style={"height": "250px", "width": "250px", "right": "0px"},
)
current_filter = "none"
# Analytics table
if not analytics_input:
analytics_input = ""
table_output = get_table(current_compliance, table)
overall_status_result_graph = get_graph(pie_1, "Overall Status Result")
security_level_graph = get_graph(
pie_2, f"Top 5 failed {current_filter} by findings"
)
return (
table_output,
overall_status_result_graph,
security_level_graph,
account_filter,
account_filter_options,
region_filter_analytics,
region_filter_options,
date_filter_analytics,
options_date,
)
def get_graph(pie, title):
return [
html.Span(
title,
className="text-center text-prowler-stone-900 uppercase text-xs font-bold",
),
html.Div(
[pie],
className="",
style={
"display": "flex",
"justify-content": "center",
"align-items": "center",
"margin-top": "7%",
},
),
]
def get_bar_graph(df, column_name):
df = df[df["STATUS"] == "FAIL"]
df = df.groupby([column_name, "STATUS"]).size().reset_index(name="counts")
df = df.sort_values(by=["counts"], ascending=True)
# take the top 5
df = df.tail(5)
colums = df[column_name].unique()
# Cut the text if it is too long
for i in range(len(colums)):
if len(colums[i]) > 15:
colums[i] = colums[i][:15] + "..."
fig = px.bar(
df,
x="counts",
y=colums,
color="STATUS",
color_discrete_map={"FAIL": fail_color},
orientation="h",
)
fig.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=True,
showlegend=False,
xaxis_title=None,
yaxis_title=None,
font=dict(size=14, color="#292524"),
hoverlabel=dict(font_size=12),
paper_bgcolor="#FFF",
)
return dcc.Graph(
figure=fig,
config={"displayModeBar": False},
style={"height": "20rem", "width": "40rem"},
)
def get_pie(df):
# Define custom colors
color_mapping = {
"FAIL": fail_color,
"PASS": pass_color,
"INFO": info_color,
"WARN": "#260000",
"MANUAL": manual_color,
}
# Use the color_discrete_map parameter to map categories to custom colors
fig = px.pie(
df,
names="STATUS",
values="counts",
hole=0.7,
color="STATUS",
color_discrete_map=color_mapping,
)
fig.update_traces(
hovertemplate=None,
textposition="outside",
textinfo="percent+label",
rotation=50,
)
fig.update_layout(
margin=dict(l=0, r=0, t=0, b=0),
autosize=True,
showlegend=False,
font=dict(size=14, color="#292524"),
hoverlabel=dict(font_size=12),
paper_bgcolor="#FFF",
)
pie = dcc.Graph(
figure=fig,
config={"displayModeBar": False},
style={"height": "20rem", "width": "20rem"},
)
return pie
def get_table(current_compliance, table):
return [
html.Div(
[
html.H5(
f"{current_compliance}",
className="text-prowler-stone-900 text-md font-bold uppercase mb-4",
),
table,
],
className="relative flex flex-col bg-white shadow-provider rounded-xl px-4 py-3 flex-wrap w-full",
),
]
File diff suppressed because it is too large Load Diff
+179
View File
@@ -0,0 +1,179 @@
/*
/*
/*
/*
/* Use this file to add custom styles using Tailwind's utility classes. */
@tailwind base;
@tailwind components;
@tailwind utilities;
#_dash-app-content {
@apply bg-prowler-stone-500;
}
@layer components {
.custom-grid {
grid-template-columns: minmax(0, 16fr) repeat(11, minmax(0, 11fr));
}
.custom-grid-large {
grid-template-columns: minmax(0, 10fr) repeat(11, minmax(0, 11fr));
}
/* Styles for the table in the overview page */
.table-overview thead {
display: table;
width: 100%;
table-layout: fixed;
}
.table-overview tbody {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.table-overview tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
/* Styles for thead */
.table-overview th {
@apply bg-prowler-stone-900 text-sm py-3 font-bold;
}
.table-overview td {
@apply text-prowler-stone-900 bg-prowler-white text-sm py-2 font-bold;
}
/* Check ID */
.table-overview td:nth-child(1),
.table-overview th:nth-child(1) {
@apply w-[52%];
}
/* Severity */
.table-overview td:nth-child(2),
.table-overview th:nth-child(2) {
@apply w-[8%] capitalize;
}
/* Status */
.table-overview td:nth-child(3),
.table-overview th:nth-child(3) {
@apply w-[7%];
}
.table-overview td:nth-child(3) {
@apply font-bold text-prowler-error;
}
/* Region */
.table-overview td:nth-child(4),
.table-overview th:nth-child(4) {
@apply w-[9%];
}
/* Service */
.table-overview td:nth-child(5),
.table-overview th:nth-child(5) {
@apply w-[6%];
}
/* Provider */
.table-overview td:nth-child(6),
.table-overview th:nth-child(6) {
@apply w-[7%];
}
/* Account ID */
.table-overview td:nth-child(7),
.table-overview th:nth-child(7) {
@apply w-[11%];
}
}
/* Styles for the accordion in the compliance page */
#_dash-app-content .accordion .accordion-header .accordion-button {
@apply text-prowler-stone-900 inline-block px-4 text-xs font-bold uppercase transition-all rounded-lg bg-prowler-stone-300 hover:bg-prowler-stone-900/10;
}
#_dash-app-content .accordion .accordion-item {
@apply text-prowler-stone-900 bg-prowler-white rounded-lg;
}
#_dash-app-content .accordion .accordion-button:not(.collapsed) {
@apply text-prowler-stone-900 bg-prowler-stone-500;
}
#_dash-app-content .accordion .dash-table-container {
@apply grid;
}
#_dash-app-content .accordion table {
@apply rounded-lg;
}
/* Styles for thead */
#_dash-app-content .accordion th {
@apply text-prowler-white text-left bg-prowler-stone-900 text-xs py-1 font-bold;
}
/* Styles for td */
#_dash-app-content .accordion td {
@apply text-prowler-stone-900 text-left bg-prowler-white text-xs py-1 font-light;
}
/* Styles for table cells */
#_dash-app-content .accordion table tbody thead,
#_dash-app-content .accordion table tbody tr {
@apply w-full;
}
/* Check ID */
#_dash-app-content .accordion table th:nth-child(1) {
@apply w-[60%];
}
/* Status */
#_dash-app-content .accordion table th:nth-child(2) {
@apply w-[10%] text-center;
}
#_dash-app-content .accordion table td:nth-child(2) {
@apply text-center;
}
/* Region */
#_dash-app-content .accordion table th:nth-child(3) {
@apply w-[10%];
}
/* Account ID */
#_dash-app-content .accordion table th:nth-child(4) {
@apply w-[10%];
}
/* Resource ID */
#_dash-app-content .accordion table th:nth-child(5) {
@apply w-[10%];
}
#_dash-app-content .compliance-data-layout,
#_dash-app-content .accordion-body,
#_dash-app-content .compliance-data-layout .accordion.accordion-flush {
@apply grid gap-y-4;
}
#_dash-app-content .accordion-inner--child,
#_dash-app-content .accordion-inner {
@apply relative;
}
#_dash-app-content .info-bar {
@apply absolute left-1/2 transform -translate-x-1/2 top-2 h-8 z-50;
}
#_dash-app-content .info-bar-child {
@apply absolute right-6 top-2 w-auto h-8 z-50;
}
@layer utilities {
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
+90
View File
@@ -0,0 +1,90 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./assets/**/*.{py,html,js}",
"./components/**/*.{py,html,js}",
"./pages/**/*.{py,html,js}",
"./utils/**/*.{py,html,js}",
"./app.py",
],
theme: {
extend: {
colors: {
prowler: {
stone: {
950: "#1C1917",
900: "#292524",
500: "#E7E5E4",
300: "#F5F5F4",
},
gray: {
900: "#9bAACF",
700: "#BEC8E4",
500: "#C8D0E7",
300: "#E4EBF5",
},
status: {
passed: "#1FB53F",
failed: "#A3231F",
},
lime: "#84CC16",
white: "#FFFFFF",
error: "#B91C1C",
},
},
fontSize: {
'3xs': '0.625rem', // 10px
'2xs': '0.6875rem', // 11px
xs: '0.75rem', // 12px
sm: '0.875rem', // 14px
base: '1rem', // 16px
lg: '1.125rem', // 18px
xl: '1.25rem', // 20px
'2xl': '1.375rem', // 22px
'2xxl': '1.5rem', // 24px
'3xl': '1.75rem', // 28px
'4xl': '2rem', // 32px
'5xl': '2.25rem', // 36px
'6xl': '2.75rem', // 44px
'7xl': '3.5rem' // 56px
},
fontWeight: {
light: 300,
regular: 400,
medium: 500,
bold: 700,
heavy: 800
},
lineHeight: {
14: "0.875rem", // 14px
22: "1.375rem", // 22px
26: "1.625rem", // 26px
28: "1.75rem", // 28px
30: "1.875rem", // 30px
32: "2rem", // 32px
34: "2.125rem", // 34px
36: "2.25rem", // 36px
40: "2.5rem", // 40px
44: "2.75rem", // 44px
48: "3rem", // 48px
56: "3.5rem", // 56px
68: "4.25rem", // 68px
},
boxShadow: {
"provider":
".3rem .3rem .6rem #c8d0e7, -.2rem -.2rem .5rem #FFF",
"box-up":
"0.3rem 0.3rem 0.6rem #c8d0e7, -0.2rem -0.2rem 0.5rem #FFF",
"box-down":
"inset .2rem .2rem .5rem #c8d0e7, inset -.2rem -.2rem .5rem #FFF",
},
backgroundImage: {
"gradient-passed":
"linear-gradient(127.43deg, #F1F5F8 -177.68%, #4ADE80 87.35%)",
"gradient-failed":
"linear-gradient(127.43deg, #F1F5F8 -177.68%, #EF4444 87.35%)",
},
},
},
plugins: [],
};
+7 -4
View File
@@ -102,7 +102,7 @@ All the checks MUST fill the `report.status` and `report.status_extended` with t
- Status -- `report.status`
- `PASS` --> If the check is passing against the configured value.
- `FAIL` --> If the check is passing against the configured value.
- `INFO` --> This value cannot be used unless a manual operation is required in order to determine if the `report.status` is whether `PASS` or `FAIL`.
- `MANUAL` --> This value cannot be used unless a manual operation is required in order to determine if the `report.status` is whether `PASS` or `FAIL`.
- Status Extended -- `report.status_extended`
- MUST end in a dot `.`
- MUST include the service audited with the resource and a brief explanation of the result generated, e.g.: `EC2 AMI ami-0123456789 is not public.`
@@ -125,7 +125,7 @@ All the checks MUST fill the `report.resource_id` and `report.resource_arn` with
- Resource ARN -- `report.resource_arn`
- AWS Account --> Root ARN `arn:aws:iam::123456789012:root`
- AWS Resource --> Resource ARN
- Root resource --> Root ARN `arn:aws:iam::123456789012:root`
- Root resource --> Resource Type ARN `f"arn:{service_client.audited_partition}:<service_name>:{service_client.region}:{service_client.audited_account}:<resource_type>"`
- GCP
- Resource ID -- `report.resource_id`
- GCP Resource --> Resource ID
@@ -196,14 +196,17 @@ aws:
As you can see in the above code, within the service client, in this case the `ec2_client`, there is an object called `audit_config` which is a Python dictionary containing the values read from the configuration file.
In order to use it, you have to check first if the value is present in the configuration file. If the value is not present, you can create it in the `config.yaml` file and then, read it from the check.
> It is mandatory to always use the `dictionary.get(value, default)` syntax to set a default value in the case the configuration value is not present.
???+ note
It is mandatory to always use the `dictionary.get(value, default)` syntax to set a default value in the case the configuration value is not present.
## Check Metadata
Each Prowler check has metadata associated which is stored at the same level of the check's folder in a file called A `check_name.metadata.json` containing the check's metadata.
> We are going to include comments in this example metadata JSON but they cannot be included because the JSON format does not allow comments.
???+ note
We are going to include comments in this example metadata JSON but they cannot be included because the JSON format does not allow comments.
```json
{
+45
View File
@@ -0,0 +1,45 @@
# Debugging
Debugging in Prowler make things easier!
If you are developing Prowler, it's possible that you will encounter some situations where you have to inspect the code in depth to fix some unexpected issues during the execution. To do that, if you are using VSCode you can run the code using the integrated debugger. Please, refer to this [documentation](https://code.visualstudio.com/docs/editor/debugging) for guidance about the debugger in VSCode.
The following file is an example of the [debugging configuration](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations) file that you can add to [Virtual Studio Code](https://code.visualstudio.com/).
This file should inside the *.vscode* folder and its name has to be *launch.json*:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "prowler.py",
"args": [
"aws",
"-f",
"eu-west-1",
"--service",
"cloudwatch",
"--log-level",
"ERROR",
"-p",
"dev",
],
"console": "integratedTerminal",
"justMyCode": false
},
{
"name": "Python: Debug Tests",
"type": "python",
"request": "launch",
"program": "${file}",
"purpose": [
"debug-test"
],
"console": "integratedTerminal",
"justMyCode": false
}
]
}
```
+1 -1
View File
@@ -1,6 +1,6 @@
## Contribute with documentation
We use `mkdocs` to build this Prowler documentation site so you can easily contribute back with new docs or improving them.
We use `mkdocs` to build this Prowler documentation site so you can easily contribute back with new docs or improving them. To install all necessary dependencies use `poetry install --with docs`.
1. Install `mkdocs` with your favorite package manager.
2. Inside the `prowler` repository folder run `mkdocs serve` and point your browser to `http://localhost:8000` and you will see live changes to your local copy of this documentation site.
+5 -3
View File
@@ -1,6 +1,6 @@
# Developer Guide
You can extend Prowler in many different ways, in most cases you will want to create your own checks and compliance security frameworks, here is where you can learn about how to get started with it. We also include how to create custom outputs, integrations and more.
You can extend Prowler Open Source in many different ways, in most cases you will want to create your own checks and compliance security frameworks, here is where you can learn about how to get started with it. We also include how to create custom outputs, integrations and more.
## Get the code and install all dependencies
@@ -16,7 +16,7 @@ pip install poetry
```
Then install all dependencies including the ones for developers:
```
poetry install
poetry install --with dev
poetry shell
```
@@ -31,7 +31,9 @@ You should get an output like the following:
pre-commit installed at .git/hooks/pre-commit
```
Before we merge any of your pull requests we pass checks to the code, we use the following tools and automation to make sure the code is secure and dependencies up-to-dated (these should have been already installed if you ran `pipenv install -d`):
Before we merge any of your pull requests we pass checks to the code, we use the following tools and automation to make sure the code is secure and dependencies up-to-dated:
???+ note
These should have been already installed if you ran `poetry install --with dev`
- [`bandit`](https://pypi.org/project/bandit/) for code security review.
- [`safety`](https://pypi.org/project/safety/) and [`dependabot`](https://github.com/features/security) for dependencies.
@@ -23,7 +23,7 @@ Each file version of a framework will have the following structure at high level
"Requirements": [
{
"Id": "<unique-id>",
"Description": "Requiemente full description",
"Description": "Requirement full description",
"Checks": [
"Here is the prowler check or checks that is going to be executed"
],
@@ -38,4 +38,4 @@ Each file version of a framework will have the following structure at high level
}
```
Finally, to have a proper output file for your reports, your framework data model has to be created in `prowler/lib/outputs/models.py` and also the CLI table output in `prowler/lib/outputs/compliance.py`.
Finally, to have a proper output file for your reports, your framework data model has to be created in `prowler/lib/outputs/models.py` and also the CLI table output in `prowler/lib/outputs/compliance.py`. Also, you need to add a new conditional in `prowler/lib/outputs/file_descriptors.py` if you create a new CSV model.
+12 -8
View File
@@ -40,13 +40,15 @@ Other commands to run tests:
- Run tests for a provider service: `pytest -n auto -vvv -s -x tests/providers/<provider>/services/<service>`
- Run tests for a provider check: `pytest -n auto -vvv -s -x tests/providers/<provider>/services/<service>/<check>`
> Refer to the [pytest documentation](https://docs.pytest.org/en/7.1.x/getting-started.html) documentation for more information.
???+ note
Refer to the [pytest documentation](https://docs.pytest.org/en/7.1.x/getting-started.html) documentation for more information.
## AWS
For the AWS provider we have ways to test a Prowler check based on the following criteria:
> Note: We use and contribute to the [Moto](https://github.com/getmoto/moto) library which allows us to easily mock out tests based on AWS infrastructure. **It's awesome!**
???+ note
We use and contribute to the [Moto](https://github.com/getmoto/moto) library which allows us to easily mock out tests based on AWS infrastructure. **It's awesome!**
- AWS API calls covered by [Moto](https://github.com/getmoto/moto):
- Service tests with `@mock_<service>`
@@ -195,7 +197,8 @@ class Test_iam_password_policy_uppercase:
If the IAM service for the check's we want to test is not covered by Moto, we have to inject the objects in the service client using [MagicMock](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock). As we have pointed above, we cannot instantiate the service since it will make real calls to the AWS APIs.
> The following example uses the IAM GetAccountPasswordPolicy which is covered by Moto but this is only for demonstration purposes.
???+ note
The following example uses the IAM GetAccountPasswordPolicy which is covered by Moto but this is only for demonstration purposes.
The following code shows how to use MagicMock to create the service objects.
@@ -325,7 +328,8 @@ class Test_iam_password_policy_uppercase:
Note that this does not use Moto, to keep it simple, but if you use any `moto`-decorators in addition to the patch, the call to `orig(self, operation_name, kwarg)` will be intercepted by Moto.
> The above code comes from here https://docs.getmoto.org/en/latest/docs/services/patching_other_services.html
???+ note
The above code comes from here https://docs.getmoto.org/en/latest/docs/services/patching_other_services.html
#### Mocking more than one service
@@ -385,7 +389,7 @@ with mock.patch(
"prowler.providers.<provider>.lib.audit_info.audit_info.audit_info",
new=audit_info,
), mock.patch(
"prowler.providers.aws.services.<service>.<check>.<check>.<service>_client",
"prowler.providers.<provider>.services.<service>.<check>.<check>.<service>_client",
new=<SERVICE>(audit_info),
):
```
@@ -407,10 +411,10 @@ with mock.patch(
"prowler.providers.<provider>.lib.audit_info.audit_info.audit_info",
new=audit_info,
), mock.patch(
"prowler.providers.aws.services.<service>.<SERVICE>",
"prowler.providers.<provider>.services.<service>.<SERVICE>",
new=<SERVICE>(audit_info),
) as service_client, mock.patch(
"prowler.providers.aws.services.<service>.<service>_client.<service>_client",
"prowler.providers.<provider>.services.<service>.<service>_client.<service>_client",
new=service_client,
):
```
@@ -523,7 +527,7 @@ from unittest import mock
from uuid import uuid4
# Azure Constants
AZURE_SUBSCRIPTION = str(uuid4())
from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION
+42 -14
View File
@@ -5,7 +5,7 @@ Prowler has been written in Python using the [AWS SDK (Boto3)](https://boto3.ama
Since Prowler uses AWS Credentials under the hood, you can follow any authentication method as described [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence).
### AWS Authentication
### Authentication
Make sure you have properly configured your AWS-CLI with a valid Access Key and Region or declare AWS variables properly (or instance profile/role):
@@ -26,9 +26,8 @@ Those credentials must be associated to a user or role with proper permissions t
- `arn:aws:iam::aws:policy/SecurityAudit`
- `arn:aws:iam::aws:policy/job-function/ViewOnlyAccess`
> Moreover, some read-only additional permissions are needed for several checks, make sure you attach also the custom policy [prowler-additions-policy.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-additions-policy.json) to the role you are using.
> If you want Prowler to send findings to [AWS Security Hub](https://aws.amazon.com/security-hub), make sure you also attach the custom policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json).
???+ note
Moreover, some read-only additional permissions are needed for several checks, make sure you attach also the custom policy [prowler-additions-policy.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-additions-policy.json) to the role you are using. If you want Prowler to send findings to [AWS Security Hub](https://aws.amazon.com/security-hub), make sure you also attach the custom policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json).
### Multi-Factor Authentication
@@ -39,7 +38,7 @@ If your IAM entity enforces MFA you can use `--mfa` and Prowler will ask you to
## Azure
Prowler for azure supports the following authentication types:
Prowler for Azure supports the following authentication types:
- Service principal authentication by environment variables (Enterprise Application)
- Current az cli credentials stored
@@ -63,33 +62,61 @@ The other three cases does not need additional configuration, `--az-cli-auth` an
### Permissions
To use each one you need to pass the proper flag to the execution. Prowler fro Azure handles two types of permission scopes, which are:
To use each one you need to pass the proper flag to the execution. Prowler for Azure handles two types of permission scopes, which are:
- **Azure Active Directory permissions**: Used to retrieve metadata from the identity assumed by Prowler and future AAD checks (not mandatory to have access to execute the tool)
- **Microsoft Entra ID permissions**: Used to retrieve metadata from the identity assumed by Prowler (not mandatory to have access to execute the tool).
- **Subscription scope permissions**: Required to launch the checks against your resources, mandatory to launch the tool.
#### Azure Active Directory scope
#### Microsoft Entra ID scope
Azure Active Directory (AAD) permissions required by the tool are the following:
Microsoft Entra ID (AAD earlier) permissions required by the tool are the following:
- `Directory.Read.All`
- `Policy.Read.All`
- `UserAuthenticationMethod.Read.All`
The best way to assign it is through the azure web console:
The best way to assign it is through the Azure web console:
1. Access to Microsoft Entra ID
2. In the left menu bar, go to "App registrations"
3. Once there, in the menu bar click on "+ New registration" to register a new application
4. Fill the "Name, select the "Supported account types" and click on "Register. You will be redirected to the applications page.
![Register an Application page](../img/register-application.png)
4. Select the new application
5. In the left menu bar, select "API permissions"
6. Then click on "+ Add a permission" and select "Microsoft Graph"
7. Once in the "Microsoft Graph" view, select "Application permissions"
8. Finally, search for "Directory", "Policy" and "UserAuthenticationMethod" select the following permissions:
- `Directory.Read.All`
- `Policy.Read.All`
- `UserAuthenticationMethod.Read.All`
![EntraID Permissions](../img/AAD-permissions.png)
![AAD Permissions](../img/AAD-permissions.png)
#### Subscriptions scope
Regarding the subscription scope, Prowler by default scans all the subscriptions that is able to list, so it is required to add the following RBAC builtin roles per subscription to the entity that is going to be assumed by the tool:
Regarding the subscription scope, Prowler by default scans all the subscriptions that is able to list, so it is required to add the following RBAC builtin roles per subscription to the entity that is going to be assumed by the tool:
- `Security Reader`
- `Reader`
To assign this roles, follow the instructions:
1. Access your subscription, then select your subscription.
2. Select "Access control (IAM)".
3. In the overview, select "Roles"
![IAM Page](../img/page-IAM.png)
4. Click on "+ Add" and select "Add role assignment"
5. In the search bar, type `Security Reader`, select it and click on "Next"
6. In the Members tab, click on "+ Select members" and add the members you want to assign this role.
7. Click on "Review + assign" to apply the new role.
*Repeat these steps for `Reader` role*
## Google Cloud
### GCP Authentication
### Authentication
Prowler will follow the same credentials search as [Google authentication libraries](https://cloud.google.com/docs/authentication/application-default-credentials#search_order):
@@ -99,4 +126,5 @@ Prowler will follow the same credentials search as [Google authentication librar
Those credentials must be associated to a user or service account with proper permissions to do all checks. To make sure, add the `Viewer` role to the member associated with the credentials.
> By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned.
???+ note
By default, `prowler` will scan all accessible GCP Projects, use flag `--project-ids` to specify the projects to be scanned.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

+55 -43
View File
@@ -1,38 +1,13 @@
<p href="https://github.com/prowler-cloud/prowler">
<img align="right" src="./img/prowler-logo.png" height="100">
</p>
<br>
**Prowler** is an Open Source security tool to perform AWS, Azure and Google Cloud security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness. We have Prowler CLI (Command Line Interface) that we call Prowler Open Source and a service on top of it that we call <a href="https://prowler.com">Prowler SaaS</a>.
# Prowler Documentation
**Welcome to [Prowler Open Source v3](https://github.com/prowler-cloud/prowler/) Documentation!** 📄
For **Prowler v2 Documentation**, please go [here](https://github.com/prowler-cloud/prowler/tree/2.12.0) to the branch and its README.md.
- You are currently in the **Getting Started** section where you can find general information and requirements to help you start with the tool.
- In the [Tutorials](./tutorials/misc.md) section you will see how to take advantage of all the features in Prowler.
- In the [Contact Us](./contact.md) section you can find how to reach us out in case of technical issues.
- In the [About](./about.md) section you will find more information about the Prowler team and license.
## About Prowler
**Prowler** is an Open Source security tool to perform AWS, Azure and Google Cloud security best practices assessments, audits, incident response, continuous monitoring, hardening and forensics readiness.
It contains hundreds of controls covering CIS, PCI-DSS, ISO27001, GDPR, HIPAA, FFIEC, SOC2, AWS FTR, ENS and custom security frameworks.
[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/prowlercloud.svg?style=social&label=Follow%20%40prowlercloud)](https://twitter.com/prowlercloud)
## About ProwlerPro
<a href="https://prowler.pro"><img align="right" src="./img/prowler-pro-light.png" width="350"></a> **ProwlerPro** gives you the benefits of Prowler Open Source plus continuous monitoring, faster execution, personalized support, visualization of your data with dashboards, alerts and much more.
Visit <a href="https://prowler.pro">prowler.pro</a> for more info.
![Prowler Execution](img/short-display.png)
Prowler offers hundreds of controls covering more than 25 standards and compliance frameworks like CIS, PCI-DSS, ISO27001, GDPR, HIPAA, FFIEC, SOC2, AWS FTR, ENS and custom security frameworks.
## Quick Start
### Installation
Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-cloud/), thus can be installed using pip with `Python >= 3.9`:
Prowler is available as a project in [PyPI](https://pypi.org/project/prowler/), thus can be installed using pip with `Python >= 3.9`:
=== "Generic"
@@ -40,7 +15,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
* `Python >= 3.9`
* `Python pip >= 3.9`
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
_Commands_:
@@ -54,7 +29,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Requirements_:
* Have `docker` installed: https://docs.docker.com/get-docker/.
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
* In the command below, change `-v` to your local directory path in order to access the reports.
_Commands_:
@@ -71,7 +46,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Requirements for Ubuntu 20.04.3 LTS_:
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
* Install python 3.9 with: `sudo apt-get install python3.9`
* Remove python 3.8 to avoid conflicts if you can: `sudo apt-get remove python3.8`
* Make sure you have the python3 distutils package installed: `sudo apt-get install python3-distutils`
@@ -91,7 +66,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Requirements for Developers_:
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
* `git`, `Python >= 3.9`, `pip` and `poetry` installed (`pip install poetry`)
_Commands_:
@@ -108,7 +83,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Requirements_:
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
* Latest Amazon Linux 2 should come with Python 3.9 already installed however it may need pip. Install Python pip 3.9 with: `sudo yum install -y python3-pip`.
* Make sure setuptools for python is already installed with: `pip3 install setuptools`
@@ -125,7 +100,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Requirements_:
* `Brew` installed in your Mac or Linux
* AWS, GCP and/or Azure credentials
* AWS, GCP, Azure and/or Kubernetes credentials
_Commands_:
@@ -136,7 +111,7 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
=== "AWS CloudShell"
After the migration of AWS CloudShell from Amazon Linux 2 to Amazon Linux 2023 [[1]](https://aws.amazon.com/about-aws/whats-new/2023/12/aws-cloudshell-migrated-al2023/) [2](https://docs.aws.amazon.com/cloudshell/latest/userguide/cloudshell-AL2023-migration.html), there is no longer a need to manually compile Python 3.9 as it's already included in AL2023. Prowler can thus be easily installed following the Generic method of installation via pip. Follow the steps below to successfully execute Prowler v3 in AWS CloudShell:
After the migration of AWS CloudShell from Amazon Linux 2 to Amazon Linux 2023 [[1]](https://aws.amazon.com/about-aws/whats-new/2023/12/aws-cloudshell-migrated-al2023/) [2](https://docs.aws.amazon.com/cloudshell/latest/userguide/cloudshell-AL2023-migration.html), there is no longer a need to manually compile Python 3.9 as it's already included in AL2023. Prowler can thus be easily installed following the Generic method of installation via pip. Follow the steps below to successfully execute Prowler v4 in AWS CloudShell:
_Requirements_:
@@ -145,11 +120,16 @@ Prowler is available as a project in [PyPI](https://pypi.org/project/prowler-clo
_Commands_:
```
sudo bash
adduser prowler
su prowler
pip install prowler
prowler -v
cd /tmp || exit
prowler aws
```
> To download the results from AWS CloudShell, select Actions -> Download File and add the full path of each file. For the CSV file it will be something like `/home/cloudshell-user/output/prowler-output-123456789012-20221220191331.csv`
???+ note
To download the results from AWS CloudShell, select Actions -> Download File and add the full path of each file. For the CSV file it will be something like `/home/cloudshell-user/output/prowler-output-123456789012-20221220191331.csv`
=== "Azure CloudShell"
@@ -184,16 +164,20 @@ You can run Prowler from your workstation, an EC2 instance, Fargate or any other
![Architecture](img/architecture.png)
## Basic Usage
To run Prowler, you will need to specify the provider (e.g aws, gcp or azure):
> If no provider specified, AWS will be used for backward compatibility with most of v2 options.
To run Prowler, you will need to specify the provider (e.g `aws`, `gcp`, `azure` or `kubernetes`):
???+ note
If no provider specified, AWS will be used for backward compatibility with most of v2 options.
```console
prowler <provider>
```
![Prowler Execution](img/short-display.png)
> Running the `prowler` command without options will use your environment variable credentials, see [Requirements](./getting-started/requirements.md) section to review the credentials settings.
If you miss the former output you can use `--verbose` but Prowler v3 is smoking fast, so you won't see much ;)
???+ note
Running the `prowler` command without options will use your environment variable credentials, see [Requirements](./getting-started/requirements.md) section to review the credentials settings.
If you miss the former output you can use `--verbose` but Prowler v4 is smoking fast, so you won't see much ;
By default, Prowler will generate a CSV, JSON and HTML reports, however you can generate a JSON-ASFF (used by AWS Security Hub) report with `-M` or `--output-modes`:
@@ -217,6 +201,7 @@ For executing specific checks or services you can use options `-c`/`checks` or `
prowler azure --checks storage_blob_public_access_level_is_disabled
prowler aws --services s3 ec2
prowler gcp --services iam compute
prowler kubernetes --services etcd apiserver
```
Also, checks and services can be excluded with options `-e`/`--excluded-checks` or `--excluded-services`:
@@ -225,6 +210,7 @@ Also, checks and services can be excluded with options `-e`/`--excluded-checks`
prowler aws --excluded-checks s3_bucket_public_access
prowler azure --excluded-services defender iam
prowler gcp --excluded-services kms
prowler kubernetes --excluded-services controllermanager
```
More options and executions methods that will save your time in [Miscellaneous](tutorials/misc.md).
@@ -242,7 +228,9 @@ Use a custom AWS profile with `-p`/`--profile` and/or AWS regions which you want
```console
prowler aws --profile custom-profile -f us-east-1 eu-south-2
```
> By default, `prowler` will scan all AWS regions.
???+ note
By default, `prowler` will scan all AWS regions.
See more details about AWS Authentication in [Requirements](getting-started/requirements.md)
@@ -292,3 +280,27 @@ prowler gcp --project-ids <Project ID 1> <Project ID 2> ... <Project ID N>
```
See more details about GCP Authentication in [Requirements](getting-started/requirements.md)
## Kubernetes
Prowler allows you to scan your Kubernetes Cluster either from within the cluster or from outside the cluster.
For non in-cluster execution, you can provide the location of the KubeConfig file with the following argument:
```console
prowler kubernetes --kubeconfig-file path
```
For in-cluster execution, you can use the supplied yaml to run Prowler as a job:
```console
kubectl apply -f job.yaml
kubectl apply -f prowler-role.yaml
kubectl apply -f prowler-rolebinding.yaml
kubectl get pods --> prowler-XXXXX
kubectl logs prowler-XXXXX
```
> By default, `prowler` will scan all namespaces in your active Kubernetes context, use flag `--context` to specify the context to be scanned and `--namespaces` to specify the namespaces to be scanned.
## Prowler v2 Documentation
For **Prowler v2 Documentation**, please check it out [here](https://github.com/prowler-cloud/prowler/blob/8818f47333a0c1c1a457453c87af0ea5b89a385f/README.md).
+2 -2
View File
@@ -13,9 +13,9 @@ As an **AWS Partner** and we have passed the [AWS Foundation Technical Review (F
## Reporting Vulnerabilities
If you would like to report a vulnerability or have a security concern regarding Prowler Open Source or ProwlerPro service, please submit the information by contacting to help@prowler.pro.
If you would like to report a vulnerability or have a security concern regarding Prowler Open Source or Prowler SaaS service, please submit the information by contacting to us via [**support.prowler.com**](http://support.prowler.com).
The information you share with ProwlerPro as part of this process is kept confidential within ProwlerPro. We will only share this information with a third party if the vulnerability you report is found to affect a third-party product, in which case we will share this information with the third-party product's author or manufacturer. Otherwise, we will only share this information as permitted by you.
The information you share with the Prowler team as part of this process is kept confidential within Prowler. We will only share this information with a third party if the vulnerability you report is found to affect a third-party product, in which case we will share this information with the third-party product's author or manufacturer. Otherwise, we will only share this information as permitted by you.
We will review the submitted report, and assign it a tracking number. We will then respond to you, acknowledging receipt of the report, and outline the next steps in the process.
+2 -7
View File
@@ -19,9 +19,8 @@ Those credentials must be associated to a user or role with proper permissions t
- `arn:aws:iam::aws:policy/SecurityAudit`
- `arn:aws:iam::aws:policy/job-function/ViewOnlyAccess`
> Moreover, some read-only additional permissions are needed for several checks, make sure you attach also the custom policy [prowler-additions-policy.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-additions-policy.json) to the role you are using.
> If you want Prowler to send findings to [AWS Security Hub](https://aws.amazon.com/security-hub), make sure you also attach the custom policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json).
???+ note
Moreover, some read-only additional permissions are needed for several checks, make sure you attach also the custom policy [prowler-additions-policy.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-additions-policy.json) to the role you are using. If you want Prowler to send findings to [AWS Security Hub](https://aws.amazon.com/security-hub), make sure you also attach the custom policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json).
## Profiles
@@ -37,7 +36,3 @@ If your IAM entity enforces MFA you can use `--mfa` and Prowler will ask you to
- ARN of your MFA device
- TOTP (Time-Based One-Time Password)
## STS Endpoint Region
If you are using Prowler in AWS regions that are not enabled by default you need to use the argument `--sts-endpoint-region` to point the AWS STS API calls `assume-role` and `get-caller-identity` to the non-default region, e.g.: `prowler aws --sts-endpoint-region eu-south-2`.
+11 -4
View File
@@ -1,10 +1,14 @@
# AWS CloudShell
## Installation
After the migration of AWS CloudShell from Amazon Linux 2 to Amazon Linux 2023 [[1]](https://aws.amazon.com/about-aws/whats-new/2023/12/aws-cloudshell-migrated-al2023/) [[2]](https://docs.aws.amazon.com/cloudshell/latest/userguide/cloudshell-AL2023-migration.html), there is no longer a need to manually compile Python 3.9 as it's already included in AL2023. Prowler can thus be easily installed following the Generic method of installation via pip. Follow the steps below to successfully execute Prowler v3 in AWS CloudShell:
After the migration of AWS CloudShell from Amazon Linux 2 to Amazon Linux 2023 [[1]](https://aws.amazon.com/about-aws/whats-new/2023/12/aws-cloudshell-migrated-al2023/) [[2]](https://docs.aws.amazon.com/cloudshell/latest/userguide/cloudshell-AL2023-migration.html), there is no longer a need to manually compile Python 3.9 as it's already included in AL2023. Prowler can thus be easily installed following the Generic method of installation via pip. Follow the steps below to successfully execute Prowler v4 in AWS CloudShell:
```shell
sudo bash
adduser prowler
su prowler
pip install prowler
prowler -v
cd /tmp || exit
prowler aws
```
## Download Files
@@ -15,11 +19,14 @@ To download the results from AWS CloudShell, select Actions -> Download File and
The limited storage that AWS CloudShell provides for the user's home directory causes issues when installing the poetry dependencies to run Prowler from GitHub. Here is a workaround:
```shell
sudo bash
adduser prowler
su prowler
git clone https://github.com/prowler-cloud/prowler.git
cd prowler
pip install poetry
mkdir /tmp/pypoetry
poetry config cache-dir /tmp/pypoetry
mkdir /tmp/poetry
poetry config cache-dir /tmp/poetry
poetry shell
poetry install
python prowler.py -v
+23 -12
View File
@@ -1,21 +1,28 @@
# AWS Organizations
## Get AWS Account details from your AWS Organization
Prowler allows you to get additional information of the scanned account in CSV and JSON outputs. When scanning a single account you get the Account ID as part of the output.
Prowler allows you to get additional information of the scanned account from AWS Organizations.
If you have AWS Organizations Prowler can get your account details like Account Name, Email, ARN, Organization ID and Tags and you will have them next to every finding in the CSV and JSON outputs.
If you have AWS Organizations enabled, Prowler can get your account details like account name, email, ARN, organization id and tags and you will have them next to every finding's output.
In order to do that you can use the option `-O`/`--organizations-role <organizations_role_arn>`. See the following sample command:
In order to do that you can use the argument `-O`/`--organizations-role <organizations_role_arn>`. If this argument is not present Prowler will try to fetch that information automatically if the AWS account is a delegated administrator for the AWS Organization.
???+ note
Refer [here](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_delegate_policies.html) for more information about AWS Organizations delegated administrator.
See the following sample command:
```shell
prowler aws \
-O arn:aws:iam::<management_organizations_account_id>:role/<role_name>
```
> Make sure the role in your AWS Organizations management account has the permissions `organizations:ListAccounts*` and `organizations:ListTagsForResource`.
???+ note
Make sure the role in your AWS Organizations management account has the permissions `organizations:DescribeAccount` and `organizations:ListTagsForResource`.
In that command Prowler will scan the account and getting the account details from the AWS Organizations management account assuming a role and creating two reports with those details in JSON and CSV.
Prowler will scan the AWS account and get the account details from AWS Organizations.
In the JSON output below (redacted) you can see tags coded in base64 to prevent breaking CSV or JSON due to its format:
In the JSON output below you can see tags coded in base64 to prevent breaking CSV or JSON due to its format:
```json
"Account Email": "my-prod-account@domain.com",
@@ -25,13 +32,15 @@ In the JSON output below (redacted) you can see tags coded in base64 to prevent
"Account tags": "\"eyJUYWdzIjpasf0=\""
```
The additional fields in CSV header output are as follow:
The additional fields in CSV header output are as follows:
```csv
ACCOUNT_DETAILS_EMAIL,ACCOUNT_DETAILS_NAME,ACCOUNT_DETAILS_ARN,ACCOUNT_DETAILS_ORG,ACCOUNT_DETAILS_TAGS
```
- ACCOUNT_DETAILS_EMAIL
- ACCOUNT_DETAILS_NAME
- ACCOUNT_DETAILS_ARN
- ACCOUNT_DETAILS_ORG
- ACCOUNT_DETAILS_TAGS
## Extra: run Prowler across all accounts in AWS Organizations by assuming roles
## Extra: Run Prowler across all accounts in AWS Organizations by assuming roles
If you want to run Prowler across all accounts of AWS Organizations you can do this:
@@ -55,4 +64,6 @@ If you want to run Prowler across all accounts of AWS Organizations you can do t
done
```
> Using the same for loop it can be scanned a list of accounts with a variable like `ACCOUNTS_LIST='11111111111 2222222222 333333333'`
???+ note
Using the same for loop it can be scanned a list of accounts with a variable like:
</br>`ACCOUNTS_LIST='11111111111 2222222222 333333333'`
+9 -4
View File
@@ -6,10 +6,13 @@ By default Prowler is able to scan the following AWS partitions:
- China: `aws-cn`
- GovCloud (US): `aws-us-gov`
> To check the available regions for each partition and service please refer to the following document [aws_regions_by_service.json](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/aws/aws_regions_by_service.json)
???+ note
To check the available regions for each partition and service please refer to the following document [aws_regions_by_service.json](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/aws/aws_regions_by_service.json)
It is important to take into consideration that to scan the China (`aws-cn`) or GovCloud (`aws-us-gov`) partitions it is either required to have a valid region for that partition in your AWS credentials or to specify the regions you want to audit for that partition using the `-f/--region` flag.
> Please, refer to https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials for more information about the AWS credentials configuration.
???+ note
Please, refer to https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials for more information about the AWS credentials configuration.
Prowler can scan specific region(s) with:
```console
@@ -34,7 +37,8 @@ aws_access_key_id = XXXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXX
region = cn-north-1
```
> With this option all the partition regions will be scanned without the need of use the `-f/--region` flag
???+ note
With this option all the partition regions will be scanned without the need of use the `-f/--region` flag
## AWS GovCloud (US)
@@ -52,7 +56,8 @@ aws_access_key_id = XXXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXX
region = us-gov-east-1
```
> With this option all the partition regions will be scanned without the need of use the `-f/--region` flag
???+ note
With this option all the partition regions will be scanned without the need of use the `-f/--region` flag
## AWS ISO (US & Europe)
+5 -11
View File
@@ -30,15 +30,8 @@ Prowler can use your custom Role Session name with:
prowler aws --role-session-name <role_session_name>
```
> It defaults to `ProwlerAssessmentSession`
## STS Endpoint Region
If you are using Prowler in AWS regions that are not enabled by default you need to use the argument `--sts-endpoint-region` to point the AWS STS API calls `assume-role` and `get-caller-identity` to the non-default region, e.g.: `prowler aws --sts-endpoint-region eu-south-2`.
> Since v3.11.0, Prowler uses a regional token in STS sessions so it can scan all AWS regions without needing the `--sts-endpoint-region` argument.
> Make sure that you have enabled the AWS Region you want to scan in BOTH AWS Accounts (assumed role account and account from which you assume the role).
???+ note
It defaults to `ProwlerAssessmentSession`.
## Role MFA
@@ -51,6 +44,7 @@ If your IAM Role has MFA configured you can use `--mfa` along with `-R`/`--role
To create a role to be assumed in one or multiple accounts you can use either as CloudFormation Stack or StackSet the following [template](https://github.com/prowler-cloud/prowler/blob/master/permissions/create_role_to_assume_cfn.yaml) and adapt it.
> _NOTE 1 about Session Duration_: Depending on the amount of checks you run and the size of your infrastructure, Prowler may require more than 1 hour to finish. Use option `-T <seconds>` to allow up to 12h (43200 seconds). To allow more than 1h you need to modify _"Maximum CLI/API session duration"_ for that particular role, read more [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session).
???+ note "About Session Duration"
Depending on the amount of checks you run and the size of your infrastructure, Prowler may require more than 1 hour to finish. Use option `-T <seconds>` to allow up to 12h (43200 seconds). To allow more than 1h you need to modify _"Maximum CLI/API session duration"_ for that particular role, read more [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session).
> _NOTE 2 about Session Duration_: Bear in mind that if you are using roles assumed by role chaining there is a hard limit of 1 hour so consider not using role chaining if possible, read more about that, in foot note 1 below the table [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html).
Bear in mind that if you are using roles assumed by role chaining there is a hard limit of 1 hour so consider not using role chaining if possible, read more about that, in foot note 1 below the table [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html).
+2 -3
View File
@@ -21,6 +21,5 @@ By default Prowler sends HTML, JSON and CSV output formats, if you want to send
prowler <provider> -M csv -B my-bucket
```
> In the case you do not want to use the assumed role credentials but the initial credentials to put the reports into the S3 bucket, use `-D`/`--output-bucket-no-assume` instead of `-B`/`--output-bucket`.
> Make sure that the used credentials have `s3:PutObject` permissions in the S3 path where the reports are going to be uploaded.
???+ note
In the case you do not want to use the assumed role credentials but the initial credentials to put the reports into the S3 bucket, use `-D`/`--output-bucket-no-assume` instead of `-B`/`--output-bucket`. Make sure that the used credentials have `s3:PutObject` permissions in the S3 path where the reports are going to be uploaded.
+12 -9
View File
@@ -11,7 +11,8 @@ To enable the integration you have to perform the following steps, in _at least_
Since **AWS Security Hub** is a region based service, you will need to enable it in the region or regions you require. You can configure it using the AWS Management Console or the AWS CLI.
> Take into account that enabling this integration will incur in costs in AWS Security Hub, please refer to its pricing [here](https://aws.amazon.com/security-hub/pricing/) for more information.
???+ note
Take into account that enabling this integration will incur in costs in AWS Security Hub, please refer to its pricing [here](https://aws.amazon.com/security-hub/pricing/) for more information.
### Using the AWS Management Console
@@ -58,16 +59,16 @@ To enable **AWS Security Hub** and the **Prowler** integration you have to run t
```shell
aws securityhub enable-security-hub --region <region>
```
> For this command to work you will need the `securityhub:EnableSecurityHub` permission.
> You will need to set the AWS region where you want to enable AWS Security Hub.
???+ note
For this command to work you will need the `securityhub:EnableSecurityHub` permission. You will need to set the AWS region where you want to enable AWS Security Hub.
Once **AWS Security Hub** is enabled you will need to enable **Prowler** as partner integration to allow **Prowler** to send findings to your AWS Security Hub. You have to run the following commands using the AWS CLI:
```shell
aws securityhub enable-import-findings-for-product --region eu-west-1 --product-arn arn:aws:securityhub:<region>::product/prowler/prowler
```
> You will need to set the AWS region where you want to enable the integration and also the AWS region also within the ARN.
> For this command to work you will need the `securityhub:securityhub:EnableImportFindingsForProduct` permission.
???+ note
You will need to set the AWS region where you want to enable the integration and also the AWS region also within the ARN. For this command to work you will need the `securityhub:securityhub:EnableImportFindingsForProduct` permission.
## Send Findings
@@ -83,11 +84,12 @@ or for only one filtered region like eu-west-1:
prowler --security-hub --region eu-west-1
```
> **Note 1**: It is recommended to send only fails to Security Hub and that is possible adding `-q/--quiet` to the command. You can use, instead of the `-q/--quiet` argument, the `--send-sh-only-fails` argument to save all the findings in the Prowler outputs but just to send FAIL findings to AWS Security Hub.
???+ note
It is recommended to send only fails to Security Hub and that is possible adding `-q/--quiet` to the command. You can use, instead of the `-q/--quiet` argument, the `--send-sh-only-fails` argument to save all the findings in the Prowler outputs but just to send FAIL findings to AWS Security Hub.
> **Note 2**: Since Prowler perform checks to all regions by default you may need to filter by region when running Security Hub integration, as shown in the example above. Remember to enable Security Hub in the region or regions you need by calling `aws securityhub enable-security-hub --region <region>` and run Prowler with the option `-f/--region <region>` (if no region is used it will try to push findings in all regions hubs). Prowler will send findings to the Security Hub on the region where the scanned resource is located.
Since Prowler perform checks to all regions by default you may need to filter by region when running Security Hub integration, as shown in the example above. Remember to enable Security Hub in the region or regions you need by calling `aws securityhub enable-security-hub --region <region>` and run Prowler with the option `-f/--region <region>` (if no region is used it will try to push findings in all regions hubs). Prowler will send findings to the Security Hub on the region where the scanned resource is located.
> **Note 3**: To have updated findings in Security Hub you have to run Prowler periodically. Once a day or every certain amount of hours.
To have updated findings in Security Hub you have to run Prowler periodically. Once a day or every certain amount of hours.
### See you Prowler findings in AWS Security Hub
@@ -113,7 +115,8 @@ When you are auditing a multi-account AWS environment, you can send findings to
prowler --security-hub --role arn:aws:iam::123456789012:role/ProwlerExecutionRole
```
> Remember that the used role needs to have permissions to send findings to Security Hub. To get more information about the permissions required, please refer to the following IAM policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json)
???+ note
Remember that the used role needs to have permissions to send findings to Security Hub. To get more information about the permissions required, please refer to the following IAM policy [prowler-security-hub.json](https://github.com/prowler-cloud/prowler/blob/master/permissions/prowler-security-hub.json)
## Send only failed findings to Security Hub
+12 -12
View File
@@ -1,19 +1,19 @@
# Check Aliases
Prowler allows you to use aliases for the checks. You only have to add the `CheckAliases` key to the check's metadata with a list of the aliases:
"Provider": "<provider>",
"CheckID": "<check_id>",
"CheckTitle": "<check_title>",
"CheckAliases": [
"<check_alias_1>"
"<check_alias_2>",
...
],
...
```json title="check.metadata.json"
"Provider": "<provider>",
"CheckID": "<check_id>",
"CheckTitle": "<check_title>",
"CheckAliases": [
"<check_alias_1>"
"<check_alias_2>",
...
],
...
```
Then, you can execute the check either with its check ID or with one of the previous aliases:
```console
```shell
prowler <provider> -c/--checks <check_alias_1>
Using alias <check_alias_1> for check <check_id>...
+19 -11
View File
@@ -1,5 +1,18 @@
# Compliance
Prowler allows you to execute checks based on requirements defined in compliance frameworks.
Prowler allows you to execute checks based on requirements defined in compliance frameworks. By default, it will execute and give you an overview of the status of each compliance framework:
<img src="../img/compliance/compliance.png"/>
> You can find CSVs containing detailed compliance results inside the compliance folder within Prowler's output folder.
## Execute Prowler based on Compliance Frameworks
Prowler can analyze your environment based on a specific compliance framework and get more details, to do it, you can use option `--compliance`:
```sh
prowler <provider> --compliance <compliance_framework>
```
Standard results will be shown and additionally the framework information as the sample below for CIS AWS 1.5. For details a CSV file has been generated as well.
<img src="../img/compliance/compliance-cis-sample1.png"/>
## List Available Compliance Frameworks
In order to see which compliance frameworks are cover by Prowler, you can use option `--list-compliance`:
@@ -7,6 +20,7 @@ In order to see which compliance frameworks are cover by Prowler, you can use op
prowler <provider> --list-compliance
```
Currently, the available frameworks are:
- `aws_account_security_onboarding_aws`
- `aws_audit_manager_control_tower_guardrails_aws`
- `aws_foundational_security_best_practices_aws`
@@ -16,12 +30,16 @@ Currently, the available frameworks are:
- `cis_1.5_aws`
- `cis_2.0_aws`
- `cis_2.0_gcp`
- `cis_2.0_azure`
- `cis_2.1_azure`
- `cis_3.0_aws`
- `cis_1.8_kubernetes`
- `cisa_aws`
- `ens_rd2022_aws`
- `fedramp_low_revision_4_aws`
- `fedramp_moderate_revision_4_aws`
- `ffiec_aws`
- `aws_foundational_technical_review_aws`
- `gdpr_aws`
- `gxp_21_cfr_part_11_aws`
- `gxp_eu_annex_11_aws`
@@ -43,7 +61,6 @@ prowler <provider> --list-compliance-requirements <compliance_framework(s)>
```
Example for the first requirements of CIS 1.5 for AWS:
```
Listing CIS 1.5 AWS Compliance Requirements:
@@ -76,15 +93,6 @@ Requirement Id: 1.5
```
## Execute Prowler based on Compliance Frameworks
As we mentioned, Prowler can be execute to analyse you environment based on a specific compliance framework, to do it, you can use option `--compliance`:
```sh
prowler <provider> --compliance <compliance_framework>
```
Standard results will be shown and additionally the framework information as the sample below for CIS AWS 1.5. For details a CSV file has been generated as well.
<img src="../img/compliance-cis-sample1.png"/>
## Create and contribute adding other Security Frameworks
This information is part of the Developer Guide and can be found here: https://docs.prowler.cloud/en/latest/tutorials/developer-guide/.
+204 -8
View File
@@ -29,29 +29,58 @@ The following list includes all the AWS checks with configurable variables that
| `organizations_delegated_administrators` | `organizations_trusted_delegated_administrators` | List of Strings |
| `ecr_repositories_scan_vulnerabilities_in_latest_image` | `ecr_repository_vulnerability_minimum_severity` | String |
| `trustedadvisor_premium_support_plan_subscribed` | `verify_premium_support_plans` | Boolean |
| `config_recorder_all_regions_enabled` | `allowlist_non_default_regions` | Boolean |
| `drs_job_exist` | `allowlist_non_default_regions` | Boolean |
| `guardduty_is_enabled` | `allowlist_non_default_regions` | Boolean |
| `securityhub_enabled` | `allowlist_non_default_regions` | Boolean |
| `config_recorder_all_regions_enabled` | `mute_non_default_regions` | Boolean |
| `drs_job_exist` | `mute_non_default_regions` | Boolean |
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
| `securityhub_enabled` | `mute_non_default_regions` | Boolean |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_entropy` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_minutes` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_actions` | List of Strings |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_entropy` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_minutes` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_actions` | List of Strings |
## Azure
### Configurable Checks
The following list includes all the Azure checks with configurable variables that can be changed in the configuration yaml file:
| Check Name | Value | Type |
|---------------------------------------------------------------|--------------------------------------------------|-----------------|
| `network_public_ip_shodan` | `shodan_api_key` | String |
| `app_ensure_php_version_is_latest` | `php_latest_version` | String |
| `app_ensure_python_version_is_latest` | `python_latest_version` | String |
| `app_ensure_java_version_is_latest` | `java_latest_version` | String |
## GCP
### Configurable Checks
## Kubernetes
### Configurable Checks
The following list includes all the Azure checks with configurable variables that can be changed in the configuration yaml file:
| Check Name | Value | Type |
|---------------------------------------------------------------|--------------------------------------------------|-----------------|
| `audit_log_maxbackup` | `audit_log_maxbackup` | String |
| `audit_log_maxsize` | `audit_log_maxsize` | String |
| `audit_log_maxage` | `audit_log_maxage` | String |
| `apiserver_strong_ciphers` | `apiserver_strong_ciphers` | String |
| `kubelet_strong_ciphers_only` | `kubelet_strong_ciphers` | String |
## Config YAML File Structure
> This is the new Prowler configuration file format. The old one without provider keys is still compatible just for the AWS provider.
???+ note
This is the new Prowler configuration file format. The old one without provider keys is still compatible just for the AWS provider.
```yaml title="config.yaml"
# AWS Configuration
aws:
# AWS Global Configuration
# aws.allowlist_non_default_regions --> Allowlist Failed Findings in non-default regions for GuardDuty, SecurityHub, DRS and Config
allowlist_non_default_regions: False
# aws.mute_non_default_regions --> Mute Failed Findings in non-default regions for GuardDuty, SecurityHub, DRS and Config
mute_non_default_regions: False
# AWS IAM Configuration
# aws.iam_user_accesskey_unused --> CIS recommends 45 days
@@ -124,10 +153,177 @@ aws:
# trustedadvisor_premium_support_plan_subscribed
verify_premium_support_plans: True
# AWS CloudTrail Configuration
# aws.cloudtrail_threat_detection_privilege_escalation
threat_detection_privilege_escalation_entropy: 0.7 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.7 (70%)
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: [
"AddPermission",
"AddRoleToInstanceProfile",
"AddUserToGroup",
"AssociateAccessPolicy",
"AssumeRole",
"AttachGroupPolicy",
"AttachRolePolicy",
"AttachUserPolicy",
"ChangePassword",
"CreateAccessEntry",
"CreateAccessKey",
"CreateDevEndpoint",
"CreateEventSourceMapping",
"CreateFunction",
"CreateGroup",
"CreateJob",
"CreateKeyPair",
"CreateLoginProfile",
"CreatePipeline",
"CreatePolicyVersion",
"CreateRole",
"CreateStack",
"DeleteRolePermissionsBoundary",
"DeleteRolePolicy",
"DeleteUserPermissionsBoundary",
"DeleteUserPolicy",
"DetachRolePolicy",
"DetachUserPolicy",
"GetCredentialsForIdentity",
"GetId",
"GetPolicyVersion",
"GetUserPolicy",
"Invoke",
"ModifyInstanceAttribute",
"PassRole",
"PutGroupPolicy",
"PutPipelineDefinition",
"PutRolePermissionsBoundary",
"PutRolePolicy",
"PutUserPermissionsBoundary",
"PutUserPolicy",
"ReplaceIamInstanceProfileAssociation",
"RunInstances",
"SetDefaultPolicyVersion",
"UpdateAccessKey",
"UpdateAssumeRolePolicy",
"UpdateDevEndpoint",
"UpdateEventSourceMapping",
"UpdateFunctionCode",
"UpdateJob",
"UpdateLoginProfile",
]
# aws.cloudtrail_threat_detection_enumeration
threat_detection_enumeration_entropy: 0.7 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.7 (70%)
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: [
"DescribeAccessEntry",
"DescribeAccountAttributes",
"DescribeAvailabilityZones",
"DescribeBundleTasks",
"DescribeCarrierGateways",
"DescribeClientVpnRoutes",
"DescribeCluster",
"DescribeDhcpOptions",
"DescribeFlowLogs",
"DescribeImages",
"DescribeInstanceAttribute",
"DescribeInstanceInformation",
"DescribeInstanceTypes",
"DescribeInstances",
"DescribeInstances",
"DescribeKeyPairs",
"DescribeLogGroups",
"DescribeLogStreams",
"DescribeOrganization",
"DescribeRegions",
"DescribeSecurityGroups",
"DescribeSnapshotAttribute",
"DescribeSnapshotTierStatus",
"DescribeSubscriptionFilters",
"DescribeTransitGatewayMulticastDomains",
"DescribeVolumes",
"DescribeVolumesModifications",
"DescribeVpcEndpointConnectionNotifications",
"DescribeVpcs",
"GetAccount",
"GetAccountAuthorizationDetails",
"GetAccountSendingEnabled",
"GetBucketAcl",
"GetBucketLogging",
"GetBucketPolicy",
"GetBucketReplication",
"GetBucketVersioning",
"GetCallerIdentity",
"GetCertificate",
"GetConsoleScreenshot",
"GetCostAndUsage",
"GetDetector",
"GetEbsDefaultKmsKeyId",
"GetEbsEncryptionByDefault",
"GetFindings",
"GetFlowLogsIntegrationTemplate",
"GetIdentityVerificationAttributes",
"GetInstances",
"GetIntrospectionSchema",
"GetLaunchTemplateData",
"GetLaunchTemplateData",
"GetLogRecord",
"GetParameters",
"GetPolicyVersion",
"GetPublicAccessBlock",
"GetQueryResults",
"GetRegions",
"GetSMSAttributes",
"GetSMSSandboxAccountStatus",
"GetSendQuota",
"GetTransitGatewayRouteTableAssociations",
"GetUserPolicy",
"HeadObject",
"ListAccessKeys",
"ListAccounts",
"ListAllMyBuckets",
"ListAssociatedAccessPolicies",
"ListAttachedUserPolicies",
"ListClusters",
"ListDetectors",
"ListDomains",
"ListFindings",
"ListHostedZones",
"ListIPSets",
"ListIdentities",
"ListInstanceProfiles",
"ListObjects",
"ListOrganizationalUnitsForParent",
"ListOriginationNumbers",
"ListPolicyVersions",
"ListRoles",
"ListRoles",
"ListRules",
"ListServiceQuotas",
"ListSubscriptions",
"ListTargetsByRule",
"ListTopics",
"ListUsers",
"LookupEvents",
"Search",
]
# Azure Configuration
azure:
# Azure Network Configuration
# azure.network_public_ip_shodan
shodan_api_key: null
# Azure App Configuration
# azure.app_ensure_php_version_is_latest
php_latest_version: "8.2"
# azure.app_ensure_python_version_is_latest
python_latest_version: "3.12"
# azure.app_ensure_java_version_is_latest
java_latest_version: "17"
# GCP Configuration
gcp:
# GCP Compute Configuration
# gcp.compute_public_address_shodan
shodan_api_key: null
```
+4
View File
@@ -31,6 +31,10 @@ CustomChecksMetadata:
Checks:
compute_instance_public_ip:
Severity: critical
kubernetes:
Checks:
apiserver_anonymous_requests:
Severity: low
```
## Usage
+96
View File
@@ -0,0 +1,96 @@
# Dashboard
Prowler allows you to run your own local dashboards using the csv outputs provided by Prowler
```sh
prowler dashboard
```
???+ note
You can expose the `dashboard` server in another address using the `HOST` environment variable.
To run Prowler local dashboard with Docker, use:
```sh
docker run --env HOST=0.0.0.0 --publish 127.0.0.1:11666:11666 toniblyx/prowler:latest dashboard
```
???+ note
**Remember that the `dashboard` server is not authenticated, if you expose it to the internet, you are running it at your own risk.**
The banner and additional info about the dashboard will be shown on your console:
<img src="../img/dashboard/dashboard-banner.png">
## Overview Page
The overview page provides a full impression of your findings obtained from Prowler:
<img src="../img/dashboard/dashboard-overview.png">
In this page you can do multiple functions:
* Apply filters (Assessment Date / Account / Region)
* See wich files has been scanned to generate the dashboard placing your mouse on the `?` icon:
<img src="../img/dashboard/dashboard-files-scanned.png">
* Download the `Top 25 Failed Findings by Severity` table using the button `DOWNLOAD THIS TABLE AS CSV`
## Compliance Page
This page shows all the info related to the compliance selected, you can apply multiple filters depending on your preferences.
<img src="../img/dashboard/dashboard-compliance.png">
To add your own compliance to compliance page, add a file with the compliance name (using `_` instead of `.`) to the path `/dashboard/compliance`.
In this file use the format present in the others compliance files to create the table. Example for CIS 2.0:
```python
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
```
## S3 Integration
If you are a Prowler Saas customer and you want to use your data from your S3 bucket, you can run:
```sh
aws s3 cp s3://<your-bucket>/output/csv ./output --recursive
```
to load the dashboard with the new files.
## Output Path
Prowler will use the outputs from the folder `/output` (for common prowler outputs) and `/output/compliance` (for prowler compliance outputs) to generate the dashboard.
To change the path modify the values `folder_path_overview` or `folder_path_compliance` from `/dashboard/config.py`
## Output Support
Prowler dashboard supports the detailed outputs:
| Provider | V3 | V4 | COMPLIANCE-V3 | COMPLIANCE-V4|
|---|---|---|---|---|
| AWS | ✅ | ✅ | ✅ | ✅ |
| Azure | ❌ | ✅ | ❌ | ✅ |
| Kubernetes | ❌ | ✅ | ❌ | ✅ |
| GCP | ❌ | ✅ | ❌ | ✅ |
+2 -1
View File
@@ -13,7 +13,8 @@ Otherwise, you can generate and download Service Account keys in JSON format (re
prowler gcp --credentials-file path
```
> `prowler` will scan the GCP project associated with the credentials.
???+ note
`prowler` will scan the GCP project associated with the credentials.
Prowler will follow the same credentials search as [Google authentication libraries](https://cloud.google.com/docs/authentication/application-default-credentials#search_order):

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

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