From 89fe86794491a7200af061d90a8cdf65c2c0348b Mon Sep 17 00:00:00 2001 From: Kay Agahd Date: Wed, 8 Apr 2026 10:55:55 +0200 Subject: [PATCH 01/36] fix(aws): recognize service-specific condition keys as restrictive in is_policy_public (#10600) Co-authored-by: Claude Opus 4.6 --- prowler/CHANGELOG.md | 1 + .../providers/aws/services/iam/lib/policy.py | 10 + .../aws/services/iam/lib/policy_test.py | 174 ++++++++++++++++++ 3 files changed, 185 insertions(+) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index c8b454ceaf..37b00bc5bd 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -33,6 +33,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `--list-checks` and `--list-checks-json` now include `threat-detection` category checks in their output [(#10578)](https://github.com/prowler-cloud/prowler/pull/10578) - Missing `__init__.py` in `codebuild_project_uses_allowed_github_organizations` check preventing discovery by `--list-checks` [(#10584)](https://github.com/prowler-cloud/prowler/pull/10584) - Azure Key Vault checks emitting incorrect findings for keys, secrets, and vault logging [(#10332)](https://github.com/prowler-cloud/prowler/pull/10332) +- `is_policy_public` now recognizes `kms:CallerAccount`, `kms:ViaService`, `aws:CalledVia`, `aws:CalledViaFirst`, and `aws:CalledViaLast` as restrictive condition keys, fixing false positives in `kms_key_policy_is_not_public` and other checks that use `is_condition_block_restrictive` [(#10600)](https://github.com/prowler-cloud/prowler/pull/10600) - `_enabled_regions` empty-set bug in `AwsProvider.generate_regional_clients` creating boto3 clients for all 36 AWS regions instead of the audited ones, causing random CI timeouts and slow test runs [(#10598)](https://github.com/prowler-cloud/prowler/pull/10598) - Retrieve only the latest version from a package in AWS CodeArtifact [(#10243)](https://github.com/prowler-cloud/prowler/pull/10243) diff --git a/prowler/providers/aws/services/iam/lib/policy.py b/prowler/providers/aws/services/iam/lib/policy.py index d8806f280b..ecf09d312f 100644 --- a/prowler/providers/aws/services/iam/lib/policy.py +++ b/prowler/providers/aws/services/iam/lib/policy.py @@ -617,6 +617,11 @@ def is_condition_block_restrictive( "aws:sourceorgpaths", "aws:userid", "aws:username", + "aws:calledvia", + "aws:calledviafirst", + "aws:calledvialast", + "kms:calleraccount", + "kms:viaservice", "s3:resourceaccount", "lambda:eventsourcetoken", # For Alexa Home functions, a token that the invoker must supply. ], @@ -635,6 +640,11 @@ def is_condition_block_restrictive( "aws:sourceorgpaths", "aws:userid", "aws:username", + "aws:calledvia", + "aws:calledviafirst", + "aws:calledvialast", + "kms:calleraccount", + "kms:viaservice", "s3:resourceaccount", "lambda:eventsourcetoken", ], diff --git a/tests/providers/aws/services/iam/lib/policy_test.py b/tests/providers/aws/services/iam/lib/policy_test.py index afea8ca658..50cca4cbad 100644 --- a/tests/providers/aws/services/iam/lib/policy_test.py +++ b/tests/providers/aws/services/iam/lib/policy_test.py @@ -1413,6 +1413,115 @@ class Test_Policy: condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER ) + def test_condition_parser_string_equals_aws_CalledVia_str(self): + condition_statement = { + "StringEquals": {"aws:CalledVia": "cloudformation.amazonaws.com"} + } + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + + def test_condition_parser_string_equals_aws_CalledViaFirst_str(self): + condition_statement = { + "StringEquals": {"aws:CalledViaFirst": "cloudformation.amazonaws.com"} + } + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + + def test_condition_parser_string_equals_aws_CalledViaLast_str(self): + condition_statement = { + "StringEquals": {"aws:CalledViaLast": "glue.amazonaws.com"} + } + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + + def test_condition_parser_string_like_aws_CalledVia_str(self): + condition_statement = {"StringLike": {"aws:CalledVia": "*.amazonaws.com"}} + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + + def test_condition_parser_string_equals_kms_CallerAccount_str(self): + condition_statement = { + "StringEquals": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_kms_CallerAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_kms_CallerAccount_list(self): + condition_statement = { + "StringEquals": {"kms:CallerAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_kms_CallerAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "kms:CallerAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_kms_ViaService_str(self): + condition_statement = { + "StringEquals": {"kms:ViaService": "glue.eu-central-1.amazonaws.com"} + } + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + + def test_condition_parser_string_like_kms_CallerAccount_str(self): + condition_statement = { + "StringLike": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_kms_CallerAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_kms_ViaService_str(self): + condition_statement = {"StringLike": {"kms:ViaService": "glue.*.amazonaws.com"}} + assert is_condition_block_restrictive( + condition_statement, + TRUSTED_AWS_ACCOUNT_NUMBER, + is_cross_account_allowed=True, + ) + def test_condition_parser_two_lists_unrestrictive(self): condition_statement = { "StringLike": { @@ -2357,6 +2466,71 @@ class Test_Policy: trusted_ips=["1.2.3.4", "5.6.7.8"], ) + def test_is_policy_public_kms_caller_account_and_via_service(self): + policy = { + "Version": "2008-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:CreateGrant", + "kms:DescribeKey", + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "kms:ViaService": "glue.eu-central-1.amazonaws.com", + "kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER, + } + }, + }, + ], + } + assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER) + + def test_is_policy_public_kms_caller_account_only(self): + policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": ["kms:Decrypt"], + "Resource": "*", + "Condition": { + "StringEquals": { + "kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER, + } + }, + }, + ], + } + assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER) + + def test_is_policy_public_kms_via_service_without_account_restriction(self): + policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": ["kms:Decrypt"], + "Resource": "*", + "Condition": { + "StringEquals": { + "kms:ViaService": "glue.eu-central-1.amazonaws.com", + } + }, + }, + ], + } + assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER) + def test_check_admin_access(self): policy = { "Version": "2012-10-17", From e6aedcb207038bfc621777cf76e2eb981c6149d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pe=C3=B1a?= Date: Wed, 8 Apr 2026 11:04:57 +0200 Subject: [PATCH 02/36] feat(api): support sort by delta on finding-groups endpoints (#10606) --- api/CHANGELOG.md | 1 + api/src/backend/api/tests/test_views.py | 33 +++++++++++++++++++++++++ api/src/backend/api/v1/views.py | 16 +++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 4704532d22..54b589e496 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the **Prowler API** are documented in this file. - Filter RBAC role lookup by `tenant_id` to prevent cross-tenant privilege leak [(#10491)](https://github.com/prowler-cloud/prowler/pull/10491) - `VALKEY_SCHEME`, `VALKEY_USERNAME`, and `VALKEY_PASSWORD` environment variables to configure Celery broker TLS/auth connection details for Valkey/ElastiCache [(#10420)](https://github.com/prowler-cloud/prowler/pull/10420) - `Vercel` provider support [(#10190)](https://github.com/prowler-cloud/prowler/pull/10190) +- Finding groups list and latest endpoints support `sort=delta`, ordering by `new_count` then `changed_count` so groups with the most new findings rank highest [(#10606)](https://github.com/prowler-cloud/prowler/pull/10606) ### ๐Ÿ”„ Changed diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index d30e786e5f..439a355193 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -16839,6 +16839,39 @@ class TestFindingGroupViewSet: data = response.json()["data"] assert len(data) > 0 + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_sort_by_delta( + self, + authenticated_client, + finding_groups_fixture, + endpoint_name, + ): + """Sort by delta orders by new_count then changed_count (lexicographic).""" + params = {"sort": "-delta"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert len(data) > 0 + + def delta_key(item): + attrs = item["attributes"] + return (attrs.get("new_count", 0), attrs.get("changed_count", 0)) + + desc_keys = [delta_key(item) for item in data] + assert desc_keys == sorted(desc_keys, reverse=True) + + # Ascending order produces the inverse arrangement + params["sort"] = "delta" + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + asc_keys = [delta_key(item) for item in response.json()["data"]] + assert asc_keys == sorted(asc_keys) + def test_finding_groups_latest_ignores_date_filters( self, authenticated_client, finding_groups_fixture ): diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 38875ccc2f..2392b818ac 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -7219,6 +7219,7 @@ class FindingGroupViewSet(BaseRLSViewSet): "check_id": "check_id", "check_title": "check_title", "severity": "severity_order", + "delta": "delta_order", "fail_count": "fail_count", "pass_count": "pass_count", "muted_count": "muted_count", @@ -7569,7 +7570,20 @@ class FindingGroupViewSet(BaseRLSViewSet): sort_param, self._FINDING_GROUP_SORT_MAP ) if ordering: - aggregated_queryset = aggregated_queryset.order_by(*ordering) + # delta_order is a virtual sort field: expand it to a + # lexicographic ordering by (new_count, changed_count) so groups + # with more new findings rank higher, with changed_count as the + # tie-breaker (preserves the "new > changed" priority used by + # the resources endpoint, but driven by the actual counters). + expanded_ordering = [] + for field in ordering: + if field.lstrip("-") == "delta_order": + sign = "-" if field.startswith("-") else "" + expanded_ordering.append(f"{sign}new_count") + expanded_ordering.append(f"{sign}changed_count") + else: + expanded_ordering.append(field) + aggregated_queryset = aggregated_queryset.order_by(*expanded_ordering) else: aggregated_queryset = aggregated_queryset.order_by( "-fail_count", "-severity_order", "check_id" From 1d4388523022b808bf347677227e8de70aa3d20d Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Wed, 8 Apr 2026 11:05:28 +0200 Subject: [PATCH 03/36] docs: update architecture diagram (#10604) --- README.md | 5 ++- .../products/img/prowler-app-architecture.png | Bin 196406 -> 0 bytes docs/getting-started/products/prowler-app.mdx | 5 ++- .../products/prowler-app-architecture.mmd | 37 ++++++++++++++++++ .../products/prowler-app-architecture.png | Bin 196406 -> 274761 bytes 5 files changed, 45 insertions(+), 2 deletions(-) delete mode 100644 docs/getting-started/products/img/prowler-app-architecture.png create mode 100644 docs/images/products/prowler-app-architecture.mmd diff --git a/README.md b/README.md index 90003e7055..79b336bfbd 100644 --- a/README.md +++ b/README.md @@ -317,7 +317,10 @@ python prowler-cli.py -v - **Prowler SDK**: A Python SDK designed to extend the functionality of the Prowler CLI for advanced capabilities. - **Prowler MCP Server**: A Model Context Protocol server that provides AI tools for Lighthouse, the AI-powered security assistant. This is a critical dependency for Lighthouse functionality. -![Prowler App Architecture](docs/products/img/prowler-app-architecture.png) +![Prowler App Architecture](docs/images/products/prowler-app-architecture.png) + + + ## Prowler CLI diff --git a/docs/getting-started/products/img/prowler-app-architecture.png b/docs/getting-started/products/img/prowler-app-architecture.png deleted file mode 100644 index 889bc0da880ce4ccba81be257481333b2bb65e20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196406 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 a)gPVIdCz8TR&Hj2KN>2!%DIXbe*Xhh5J?yS diff --git a/docs/getting-started/products/prowler-app.mdx b/docs/getting-started/products/prowler-app.mdx index f21e0222cd..2df6015d06 100644 --- a/docs/getting-started/products/prowler-app.mdx +++ b/docs/getting-started/products/prowler-app.mdx @@ -11,16 +11,19 @@ Prowler App is a web application that simplifies running Prowler. It provides: ## Components -Prowler App consists of three main components: +Prowler App consists of four main components: - **Prowler UI**: User-friendly web interface for running Prowler and viewing results, powered by Next.js - **Prowler API**: Backend API that executes Prowler scans and stores results, built with Django REST Framework - **Prowler SDK**: Python SDK that integrates with Prowler CLI for advanced functionality +- **Prowler MCP Server**: Model Context Protocol server that exposes AI tools for Lighthouse, the AI-powered security assistant. Required dependency for Lighthouse. Supporting infrastructure includes: - **PostgreSQL**: Persistent storage of scan results - **Celery Workers**: Asynchronous execution of Prowler scans +- **Celery Beat (API Scheduler)**: Schedules recurring scans and enqueues jobs on the broker - **Valkey**: In-memory database serving as message broker for Celery workers +- **Neo4j**: Graph database used by the Attack Paths feature to combine cloud inventory with Prowler findings (currently populated by AWS scans) ![Prowler App Architecture](/images/products/prowler-app-architecture.png) diff --git a/docs/images/products/prowler-app-architecture.mmd b/docs/images/products/prowler-app-architecture.mmd new file mode 100644 index 0000000000..bfc687b82e --- /dev/null +++ b/docs/images/products/prowler-app-architecture.mmd @@ -0,0 +1,37 @@ +flowchart TB + user([User / Security Team]) + cli([Prowler CLI]) + + subgraph APP["Prowler App"] + ui["Prowler UI
(Next.js)"] + api["Prowler API
(Django REST Framework)"] + worker["API Worker
(Celery)"] + beat["API Scheduler
(Celery Beat)"] + mcp["Prowler MCP Server
(Lighthouse AI tools)"] + end + + sdk["Prowler SDK
(Python)"] + + subgraph DATA["Data Layer"] + pg[("PostgreSQL")] + valkey[("Valkey / Redis")] + neo4j[("Neo4j")] + end + + providers["Providers"] + + user --> ui + user --> cli + ui -->|REST| api + api --> pg + api --> valkey + beat -->|enqueue jobs| valkey + valkey -->|dispatch| worker + worker --> pg + worker -->|Attack Paths| neo4j + worker -->|invokes| sdk + cli --> sdk + api -. AI tools .-> mcp + mcp -. context .-> api + + sdk --> providers diff --git a/docs/images/products/prowler-app-architecture.png b/docs/images/products/prowler-app-architecture.png index 889bc0da880ce4ccba81be257481333b2bb65e20..19bbfab0eeaffa3dd1b989013cc8ec07190a6349 100644 GIT binary patch literal 274761 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
EP47S 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%0AdI4z5nM##v+j_Z; zBbmdmTxI$=m(uPpIs=OeN#f`3ioSXTIsFy>CF6rGBQIO&TPC3D{Q?ui2N(i{HvR|y zj;hau+(3*FOTSFd;dDCYKQi9I#Y`2GvXL)`jlg3%{E35D=Iy9nqkO^BY>eKu2a3*k z$!jrz9QFjR&BgDlXLKIMrKiWvRXl4fkM>@6)bbsZi`I_TKbBzo9dLpkKHz|qWI?Ky z(V72Km${2G?g1f8>9r)8d@fSKlay_f$gC|hCawBqySM4x$ymysg?r4_T0jfAB_q?d z^)4>%XM(&V1zC||yiKJ1m`n(BXL!s)g{*$B{s`vG?0)ae7usK%xqndav^M}$>p|%L z>~c-g6yc=}c@mFM8&M|p3}Uf9DF#XpF|&mtsXT9ML}%(?R~+uViR=rorneTV`+2X9 zP+icd%q*W!Abr!qP+-Y`J#Hi2jj~Wn6uLz(MWkN-W^%n0@dR|H^qb5TN5!2>YZIR-os!U3u}__O}SSwXXr{W!)&?uBF(eRg+r)CmuqXWjK*6y(;z$m@6e)tfVe!qqp9k|Y zE8T(FRyq-BJ{?p~Vi5qb=_aQ}eNQOO0^yMSQ zw`bhb6-hfEQior`fz_3+2#uRURET>rW$n0_<&0~y0+}hl?k?EHNZcDo)+;RmoEhZ? z-M(WR)qoTsxHz6f)Rx%>&+71hW1jCh@7;3di`wNqASEaHw&sfSIqMBc8}*pcIQ^sl z#e#BYHrvp4?Xu#Tvqp}@_XHBcvNt22oAec#6-M_}ehSnc9nMcN`Ce|eH*=8i$_|p^P#_g_>>VQh#&rYuv$`AZKezkG*eYJ&##JwFIJ=B)*mV$$|w=}f( z_$i};dpR`OLT|AgDzY^?#TouI%}3jTfV!kuAGMqV+2|#Axv^+HAJGK`uM@aE7Z3@a zK^)|)Y~VVXOH;A}v6F$Jg-A13-F%hOChBI*%fxB|cD%~bzt8oL8+rW<(}hc?IK`gS za@TSrdbw-&&a5PwAWvcgHTl~aUKRdJYV#S?pM6j6Y_@3JJT6?QIdEn1?#8t{ z$HP01ErB&bMJ=on{`_;%Ov(P^!!g0^?EZrf zx>?=kdpB&HN}`A44!CL0H?C zyV&yy4q;rNoUrlS6I#fb6@i+?0Bw|^Yvi!At1$R4R`)`{s-^y1is{(+!5frU`#Yj& z-e@t;7DBri?jGB5EJ7lV9MW)tAWF6PBud`(e?XI`cFTcrmF#dpYQx2!Lde-*KHynU z$cKbjB3J=9@(?WKI08IAIgq;ptYiwvAN<^m9#TM6Q_o+d1oRlVHG+BWzVvxQm^eT{ zOOpt)Q$Ku6Km3Og98e}dbIUg^92R1_lpLM)CX_Md*xM!=jEhq@M!Km4>|~MA?SVuk zBzEM{ikS7iK@|qpxcpX2yr7Egpo`@2CxBd62jfl4 zN;=K1TB=q4fIv3%-gpp8$m4kP4RE@|7Ch^hybQ5;!@C{37V#U&9ehe@Ssi?~@k^SS zHnOuA^Y{hvz5r2Oq#|MVO!3nQLFl88Cxd2~l=SIjaFn2C6;M#qLO*E2g};zL)`IQ@ zzk7Ww;k@wI{45|5^{)=Cqtzs7#}z~UH^rm0>@ZyT0|Yb6eF8!b`TM%CTL$5EHmc3% z2x0e`L&)R79SFK!7*J=@#6^e8pGp}0oRWW~{1iEBMZ+c8qMU`YoU7n9k=o_GdU>l5kk=G4tOSowM1zE!R@+c4%W;^@ktjwgET>uAg-(a>8D7_83M#{VefbN1Fq^O zQHK~X6ObAlB)Ten5fS7bM68MHkwOTA8H8g}lJGrAFNJi(AuIs{)bl-Cp^*DavJUQX z(&t<~MF|TM@%cF{p1oFJj+Wvqzmlk5O1T8Za)kB5ZQ1uHq&Y(c!1#gVFQzyv1%L5V z+87cEMf?v@4Ek0-tpqrx-4KAT&TQq^K)~!SLV)kXSoVE1J;kw)3U>9+_qz$cUp6>p z3i#G^a}f%&7|Xth96`_b#$)9?q309-(Ja}P_0=p<5Bnz;k`@G&p0>fLMtLQXirT8f$-<&aX zQ9lVUc>}fmD^BbRLB2sqO&~PK1eDI_#5V@W=1ZH*D%Z+@&b2fLP@Wcb0wUBwn&iI} zuK!&1<5AjwZ|^*mP6%pj(LTq4onju8v6p}5enoiTGmKKH(rNKLAWc~#SuabB=V-v{ znTJh7&n6;*!bF>I5|%_6q9G~PSx`M_=47fW6k^C%jB=c>x1I3UOO3WoWdZ0f2cgOR zI$!di#B9j&KPKw9`#-iP%||2)z`9*xwmu?KwSe2dCLZs=uCfk3(Yd4Y3fUPjTmn24 zX2BA2HqqQg{+o5z6RD-^t zpr_=^5h%GgohUEYM_jCadwkM~V%eCG*wT0hIt^(KxIGor%-mBsPjH8d<@m;3zUn|s zUm0UkQ#AnSAn)$bn!-Kg4fvowcP6QqDL?(kPxA};K@9%vW#~0Uh#{A9na3+5`lab; zMdU76sU*Q2xFanwnM}m67n^h6P~Zi&Qj>^b6>m4M z_=jI+@XU$|Z^=+JkkzN$0)j@KFV;R6g-BJO5d7l?e*W&~wLktTjt5{d-HqXi-BN%+ z05p`-vg+q0grzw_vl8=-xY&2#JUHG9s`DpQv^O>iO^Z(=4y%oKNH1;hKNqZ3XelAe zzB8f9aFXz-KL=8e4&i(odxmU(afCN}Kf1}81U`(w^^%$HsEo+cA%>a1 zmb@YF(kn{8OTY-uoH;&zI;pgbCD$JO-mOVE4GqfQy%qwAp}4|lU2I4e}IE7NPG8T zKOC>7v>~8a!cm^oOH`WH2hXl(Hl_7Jybh&!zXW>l-3{{mW;y%L^#G6K66+sh3lcog z)b^__47w{&FJ5{mS5x{wFX^iiXqE@VO>4mj8898+t!J>MsD z>%_m61i=lWM)z&(YFBqRN-6hWfzD^5JU~c4z8J?}_sC$yRYNgD^#N@a8Se5le=}#a z$a7^pBgXGRPljh7a^KZSJr}PNu#ZQwBm%x_7E{%i` z_`HgE;`JZF0e|ez(IcR^R%8VFrZj@5p;Og$Ij)J3rJDvQr5aX=5zxVxp*4_dk#jTy zG@`Gfs^@MsX2F5|+N=H7lyq`fl`kUWq#&g3;D;hN1ToH*_rD(TAD1o$T)JbL)z=`r z;aSpqm^3CK9#O!yhPNZ0y-5i*`mmMkQr=N1+DuCbb13a_P7a_6!=~lttZ7~7zW{N?@XuJCH3sUcDGXn!TGkD?lYn9VakYQOD zl*r{fc;Fxgb?^jd6uxdAzk9`&YEQXa*mI#E5`-b=(sH4b>Vg7S#PVNOZl0<3>CXnk zKc+738m^7(%XDcHKB;*;pQ_H7@_=ub@t(1+s(Uwc<_K`O*SAqd7}0^Ipj+?*@TnJA z*Tke5IJj~#OkS82g!ahnQTSM$9-D*W7*7TmTDsO>;Lju6!hcWwfY#i_DME4~tpqF? zEp(E$<{K_GPD($`a`Y%44Y;zY_&(Bb#dRM_>Rp)gd6Y2$>Xa_bkvU{1e${fwSc{Fh zS*)3XV@+%$L(V8oTdVy(_N$z|d@T3?n5;9~8t9*P4+69QZ{aHlJorJwwW6f+IV4ap zE)B+0EN9TTf*`^;XQ`a{9AO@B~%Rjmp#QIIeRZ=ElT5CyqrhH-A1p;Pbgb z>HwwHD2-*!{A=%z&KM&x?k33G|2pd6+p9z0US=u0DM2aaWzdsiVZCsvD`%x|>L%p# z;nJNkD5Qi%8D=PhaassI;d{BI@3iZNSa6uUr8z-v;1)U=6ubHZ1M*q4+&HEmGLI|0 zPmiZ%K(^#99EacY|7cWh0omqj*RFf$g}e*m6v!W0AHrJ4BNKKmEDgj2gI`zsEED zzSu`69jq7w(LN5XM2K3*fi&}h!ApTA)ucc*z zi)J%5^F5T@fbD_=@2bt!nxLj<+GmoKLHI^JCoaqj=#9dmi-5)C2@qxTlxBx)iZq9*HD#!B?$m=J+#CO4@_|Jjr-r}ZWghCFuA1aC?ZI0oduq)% z@}-a1Wu*T)mBf_?(Rj}s`T>*1Re~$`4eK!zTv>I=T>4s%P{2@4Kq@F7(u@FBJxgH> zsRl?Z%n6`bJrB|9kN)HK0Hk{~!0xY8FG2@7sFRMxBx)6-USv;IG@V=zYs){b1U(Ho zlekK`>LJpIw^;z%(mElbO!bk6Rc?V65JAm8S)z4woudv zRNid}v&H^?y2vfutXH*%1$Nh0Rb;UYO>QMuVDtsd;bLD9_7B5-5nSnSnJHi)A0NDt zlJ@S9zP*Kjr=4eE5%WPbKV}W(Bfl~-<7$`fvMsbdygTfK8rYubS;;B_v&@&OMxD0z z54SffjDHUT`{nLM=Ag?{K1zdX)K4b_A%5p{ipxXqn}o=hq)*A!sU+fcE_rTUIP*YO zgn+}bI&?K*2AMoa4!7(a^L^6gJLvN)j_E?!-Gs>tp2g@EM$auaOBxLV*0LowctxXP zK2ZLyYDKQg5^yOct3fyC$a)QO6dCW%lc$~H#M&6pRiR8D*mknPJ zszUd6XC01hAVEKoXR+ys_AW7585W2_6>}RYjrm%&8@}z`(5N|Jh!l29aj*B&{y zg9-S-I#C|C{#priV9$SNRg?fBMo1Zjrj+3s@HH>Qo=vo3qmmd8IvH{!Zt}#^)$>xk zID!=b3M|!EN0kh6QNl{`g0(icMNJ0777eYW?0k-}~H>_@NDoPn>ffMsQscqvi z=*R{rzMl_u4M#GW6m=XHNP2 zvppbDvJqVe+8LJ73_LGHs$F{StDx@PX;ClY?{NwMga90;aZmjvATEvc6)I?w40JGnF3CWG44@l52flr%qK?J7r`hXl9L^K_SL*!oQT6FWX|42atlu~^47T6uG? z5pWL5L2r@FRBL#=_p5k?qz`ZK^bZyb)@w}F8&6(k#~W_pgiosFeNS}G-31Z{o0v2+ zJ-rlF)Y1fCi-V&)IFKe^|8Qca7ggl8GybCW3-i9Jqq?BpV4-T|WJtA((;!e5pL=sd z2~;7p4hT_Y*g8)7&fmgG`8CBr_Xc7o_I>M)2cIA=>~b8_39x=m zOMoJD=WMWeLmvP}QA)ubVjkDwioSZDnHWdV%yD`12J7%f+Kl4fF!$`Pa-Gc0?&+;C zJt|*+ZdfY$OcdP6Vxr-CWvK`dnh3_K4)o|3`2a`nBA411YQhFt%Aym zkrON++#b$A#tZ3Ez}3A!H%>ZW9=~`IfCYF(7eI?D8}b|FEBM(4{@hlVKe!YQUW;g) zM#;hwAV%hSF&xCoez;lR=GHj=$ z)r+Z?#n&+@vZy;qjn?-|4=qM)O2XSgfyGYU>)gnV#4~I?lMXm@`N0eSiGrEQ0F=`5 zx@td$3#p%jhYM?9_Gre3-$j%-tRzjuB;-Y95TbYXO(RUX$--&tSZOpiR@CnmgH1_E_p$-#ozGC_anEMyL7u)P2 z`C5Q9D_i&0XG&kuA=BqmEmJ(M`vxU**%y;^f=&@Xk}a)k-5OdkFd5W*Ca|P5BAmh) z>gRVhQ!zCMz3AX;GixqB`?fhamc(SH@@-^(>0%88Bq7;_nXEkO;!?Wpt|7s5W_P&h1``JK4#{TvyrrdyAV zUywS#jgcYeE9CcR9hG4lyQ4>MOVOqx?c?10*9`&N~FCJ_c@U@qe-YV{|*4w%A zW^*Z)tzSH_m1nCtC?A||a~i9Vgr8|$q9O^z5+C*ioBdk z6OJKbrn(Q=S!QN6u#Z8PG}B@uvxDe0pZUSV&c-*K@f=cFe@#S}X#O1W-v8yYJCU8) zFjj%8(rvI8YlBrT&+OfZ>)43b7axzI=|SH!tf`|5Zb>G6ta)4JX^x^aJMcWw{6$!4R z^~7OABX-*#jdPcDa%+UtMzDxyEnnVk50%ZtJfTE(H(<7wp4yELw3b^NKG%=7@q?m= zVoTi}hIO~SC0^sP16tu2m#tfFl{-Ev`vzmx=~Y{UNju1c;vl(p;hK-aF{HTr(Vl5p zY8w^A^v)IBrp_UA`X}2adNp#_=7H9aA9~J8xmVNjTH-7@kOX&J$+8y;G)H795 z9Z~7a@~D_F^+=x7A-)-|yyoDh8B9jH$AOD{ko>9|YGr^{&{3zCJGy`+BEs2&OheI6 z-+F6N?ch!ZpYbrIHtlmvg;g`Gt+HmKWVovybOd!}&G4?gzC$N-9G$#X$JP9abfsSg z35(J2>6|M+aQ}79Nf|WLa_inP%ZtWO5>UcZ5X_(IJd2T~I%h-qc`li1wnX9Hzuq&I zYM#RyT>>|$FyEGFDl^ybz$(qsFSu58U{y;^1R3U2&6`p*fWN*4t0701OWU(#&^9F( zo}dH_gkwjChv$(QoL1(Dre+mo6WZSz%I&SNv)lXrYP-_qQ{cBp0ok}Akq@Jzr-w0t&z7!KyK3QzJLA66 z5}&fW@nmWtx8_Ty6?#5)X#*wP)+yw)l|^e(eyXG^aA>zjHMSx{wb*3n^0;weWwi9c z;|g1U;RI4MR+X$-vl-QN`R65wFwoIPWJ0MUMxZF>HL43moIipKhSzQ@;wlEx(>=^2 zDzjCcr>}6-a?>6xS(&d=Z$Sh3`r%kkm@LcX&*+{4g=DyLiQ#7#iMIS$d18Lu78xM> z`I2_Sc(^oN`B7a9KmTdqYLai%&i#qf`DdGS`2w#DXEYyOVg!5l{s)5h27QQ;rFFYJqfilD8QB=)(>%IL`A28z;g2-B}0ivF{OPiE6@u%VkeYs_yB`d`{ zq`_WCWwMclS2!h3Xf_0*Y)5e&Z4^cY`~NEQia0_It_o(Ky}sWt>Kzs=o$CuFH$TM6 z^%L_BKOLzUGni2xbQQz@Ef(m{O#5r*3aXk2tvGZh+(;@9L(! znZXq5llVi$P&%X(49#hspKogLM(x_DssY;=$!#1l#06vAp}|jM{&+vry)-9c8xXcX z-hU^3nlDU(e_$5ke+u4X-B-#NX2JaNz8EY z;+={b!8Iy6i-ubVWkB&!f%%r0G^4g_*_SZ}P2KB4-g*Q1X8W!gc-rhqOF=%5Uzjs@ z8UzY%adfALM0MpL!#Zw(9^EaiiNue(=Le}u;v14@Vi}f7Vl3g$oz|PZZQHnAs`N|r zQ5t~IZjoZ!C(U*iKR8R%DX-fqcxWu_o17W-qS3dMD$+q)8u+vY8aj7C$dJ>lfGJiU zRwB6BVX#6)ch|ghd)v7WX}8hddir-daJ0=L{`qflf<=ISwG7bitmd-J7bT zzIZmQa=hicP*3RUI}L-y2lA_#4p8(XGNQ8JnhJ!d9cz(E&htEe*}q4mZ)dYp3ib_%>h>x;X)%##k9Rkh>F%4N5Xjq z_4H)jR$IP+OT5d5oEN6!y_RpmBtF}982g5lP7W5e1d?hM53*K1d%GOGT%;ml;euW) zb4<9MTf+&Ym#hrLnP7psr?kS8*ETh4HXdyiIJfg<_biG_3nqfTiCmin+bZP@rDlOZ zAuhX6s221q-J82yt9<3HBQ9+Fo6US%C>y|K@o?d@XWozsS^DnaT_{;1m4atl&$MMf zw8nnoD|f^_7vaMaHyJiwzc(1g_gq#t^-=ai`HrVE?a0R+Ih#M{z!c$^@&i^=AMVN1 zqt9ld`#NM!-NkNRty%{X=4Y$4#B(R+y5}-pKf-t&J`do#H7>->p|!7Tkky;bsbWfnkbfXRe$Y?aKkMNU*vH=Fe#?EETmGG70b;{*K{B%$rPDd z9JqsZRlhX_)cZC|CfI--H&Sz$Sf7+ZOw0i?G&-b3px8OT~S66%A6oj5*ES2 zR?DOiPwc))@xA4^62*+dg^TWh^n;8PbiGvDE@W@3_he{X8+QBd?)6wgLZZ&aNb}>f za6;jAIQ4+-(2^{hUuip=Dul-v|YO$Xtpau8lYRC2% zr6}L=kfyjE)BnYo^Q+{|kN2f7lL+1ISSKtiUkhVzebjGZ!Wvq8{$Yr`hP+s_#BzTG zx3St(i^gjevTz}ni3RJz7WhpZ34({fs8>bV~jgguv?5|nidIcsV-=M_s#1;1exk?~fUN(S5?zAsd%7na@(`Jh0GN^7qG z$Y?q=s?A;M%+23?Jw|1KbxVf|e6oQq(3A+oipf5AN5B2C;%z@sf?GakNN@gKo^}SM zoy~b0{a#^=aJ2c<*}jjCXe5&RDb>Rygx9`SWd26`zyyAUDbf~neIZN$Z;gBz@a>n3gukP)6eC%TY?rM~88rSTBvolD< zc`s6bC%Ov$gDHNefh^bff^hZzZKtVsF5B4?{+6@xk~_IMT|U=j-aG38N>0;IYT#he z!iVMYiyBI6Bi;1Q$SyFjC;l2ImxP|)*8EMa=LF8P^xUSyUt=7NfX19)7i(QK%Q>vK)rR`$$Y_L}|m0&P|CzC?wO_G^?Wc;Vk$ zXn;zl#}ZIW?XBF!pa1dsH37;|*PMd5>Od+td(D=7b;66Gy0ueLni}6&evR6F1Nw6>DOVW`Zr;mPT7S8a8p>CQk+~V4$eb%Ys290Z`Ef)tj6<-Ji8w6l zoi^1&QH$qH1)3$xoEp{6>B5ur?yn<(OGOWXQD-{q=ERQJcbO|yb|$Jt;=V#_3q6^A zs|z4}icMPj@miCFe-J(a_k?@giEzW5Nbe*%oL%M|k zwck4_H&ZtG#(B9-qoVJ92kF%&CehDtzvfw& z5sli2m>WPEMSwF-n+*FpVaMUw5(LxU)tA500Fc`sW}uAKS;!hNmX}UiL)uR7q;tJC ztrd#2`i1ru_0=zb8Tx|h5OkahB~UA>JOp|6AO?LnIg;+TZQB2qs@wy;(C0J+YA#-? zUb@fc8x|5X#RdO^<9bl}VQBP~I^Y(qocppq~bE~?XM}W!q!egM}VRDP{CPi+( z0Gt2NgYBk(^*2_j!Ehr~T8_6!+#-G{7+n3k=BywI^8M~IN=*V>Pyv0p`#Y*Ux(6`E zxYs^19COoP`eD1k)|abd>>qB#;Sp4|8#Ma$VO{m3d+I|Kz}r}UjFd-L&mY~H)8UPl$7 zh)M;}kF_)1CYL|eDl?-j4Zzb{ff6Awrr-ocJmLr9X1v%&nwCo+g29B=y!I1o<<5Gm zxK=tzHZEE0gFDu<$drb+pp@3FJvRl0Hx!WwM*$$!x-ebw`p{{HO8tpOPqIiZEyK?c zQpjWSsN~jj`jVAuji(@IQFWI0XrJx8x&+0yNFN!-bj>o$URuoSEu@rHo;3hz`oCXiH_ve^5>4@wvFi$PJ;-_@=PK09c< zhZ)N7quO{40jH+r=@q;TFwsH-3m;+z*W8lzFZCoO3MHh(Ff#VXtMA+b1h>!Dv`7j3 zAoKd6?Up3u14MGQJt-Ywp{fI$on=-ezH;P_YoBlRW)FFSF;J324l~?^@7d)(0uk2X z$&$I7PV?y(j+1Bwwy+z!EnKIwPuu}UvNs1w29&nRvRw93dXt(hKvy`4XU-IG&;>1_ zC96Xr&X%CGg}I?Qa4NQsK0Gz;`h z#IEA!vJ_r57Q-s8QMHwG{in|{nd9yJbtX`qSUKPK8#VliW1hp+yo#I5nm3>qIrI{z zehF0A)zmw|*I)<&lA6m01S-D1nCr^L+A6|ZCb`f0Tqq*F>%W5r5oyAk zK!7hP58y&9&Q_&df7y&KnU|SRA7M+X$Y-DNTvgV|b=J^IYcLT|R zV;S~I)BfpoVFy^hHUZ2rv{Q@(%h`wL`{Yo&fGpsb2{~Dnm_Nk!@r4EMybc&9eX?o9M8)hbuA4Bv)qgeW-UfD?O>D%P z!RwsMa8BuuQ<)Txk=MIfjK!KCMI5&Ak`#j6@m3~mPtN?{lcR0mWOut@iNDQ~BQikQ z*dvkGz&yjB8eLgrWFwz9kgJ+qo{V&{VNmP})}onOIiob0u7BTK2pDmK#ev7{En{K+ zlBWB^AQi(-(qicb`XjdWEn+);@b{gfx0UlKkH}u`N*BKKADd+zuX|R+`rP@b2AHFjp%OF|wHp24^WNmdiB)s^I~57qTvbaU7SNet1(> zm9Y&>1qi%x9LlY{JtV`_wQofm)pI`T@SB`myAeycuq7zr1j{|*ik8gmo8{j_(?p=p z1{8Rcjco;mkha}A@X^WI6EN%&;Bnq50CwWlR{wL(evmcrU|kRivTYF+O$^f}#x)x^ zzK&6@e3xYi)9hkzbtqjb9-@y_U+47M@MCpvMHaN|qa;Yc6nO_6jz82^#wjRIEYqmN zhv*1%oV7q5@;Eer_A71^KO`z|%=Pr({nKC@hrBzPpL=DK=Wa$a8e|!}P z4zJ+CKAZ@?a%b}P-)lem3UPS&m#B|U?%%&8fX{RR)DA%`eMoQN`S-v0b{<#rfBEhY zv|mykSNkAQ3>Fus(%;Q3j4pVk3V&Ih<5&2n`ox{z<#`2V5WFZ=-O;2x3h(#{&D;Kd zJIO;O_1*IQ(7ie86{$NRlR+*)Uf31QMjaT|xqUZOC`n9eusQb>kR0g=FUrP~T zB{Dbp^~3L{{Jky~4zMJjF-DH#M%5#l*8kVK+`GXn{cAQW#Hw$=@xE4z{{OQw5jfz| z1qYSDTsVE$j&p?HD*!mlEYVHS>h{+)f&TKJYLW7`w_s5f&o%$kH6+4%#+>;7wlYI# zRtELR4US)Z{oo&V?<$w zwtZMDhX{$yZo{RiFZOpjd2Hr&0Q!lPX%ysG$G>*hy!K@zR{!!vnxHtZfx#lMB>VfCMF|LZuo7lPY!E!&imQiIkV6r>7b1O*&BtM8X%M1x7}Ona{#kpGksow zw(hI8-(*L!wQFczbi`=@IuTAvQqXw)3O6ibbH1mI-`c=5Olz-k&L-;QjZe zD`cC`IHBTJy2nRC-2o4{mEY+NHK<`?{A>S_*|<2QNr%%)(~BE)>-Jw zMNQ3CMjm3fwf9!*2S)E=VE&a(l%~0jCf#Y(EbV-$?jYA@9zG$yh;3ppuCki1^g#(} zAR6A?&AN+AMCtkh@H-IhD^7s(ICp7VGgk|1W$`HXeN&FwhQ{nbkDW|&)E6-QKjQ27 zrC(ZzM>pDswbsIrt+r+|bt!wI&i9J>prO9!xyV~rSNa&+B0{Uy|2a2_mQ-LK*#R{y z>?9d13t;D&4>+IXRvBsZ<@Bj#sw|1l>~4OO6CFw~26?KJ#@<%g(5?$gw9PYh_$!jX9OFnm41=XLzpi-_A(FgNXNb*J#4tNU-VT7aQ= z2FPy)fZx+RYCoY1<`l`j7%8vG-wJ7Gz@8chRXiPz1Iz;Ip4|RIZl=j-_^$w;Zlh<)`I9ZkbLgj!J>zp%g$+jp);%I`z)LwpLor+Dv1r;4cl3AP%R-bInBG7 z<-9#Y=(IgT#p8k@KVoU?wXJ;Oz|UB4oiC}{yw?^Z_zmPz&uDmF*Ju)*+XSWKz3F8t zMEU~3mX*y&qPXvLBx#LxbVg>|QtFXYVa_{2cWhc#@qpG#GScF+XNqcSZ&sOC-}|p5 zuw*a+KJwsgfj(+|A^kBJsujDmJ0s~N%#iv6Z6P~=3wUh>V8SWN_yfO9km~y_NxkV) zV6Y`04}dVgv5BEaEXG6rlYknBVNhG6>k=LQHo z0pqp%!FbDdz^XFDTxVcvtp;+gQEsP8CRbBXhQuDh@EMFMtE7S}^@K zZT;Z zjjwkOjYrCnvx0Ii7)@O|f#SSYPT?^bb+~mUscw`*o@V}JCc+MOQ*c-3YXrAIXHI2) z6?(z$l^xhIS(Ndr47%gf3&yvZCj@>uWE{NZij_wzMP(I>3iZH>vCT1pqHNJgl6wsd zb^wmsK`UkY(eiOE=zn>W63d{tOOc;Gt)kLLw(l9Ms^#!$6Det^<*Oy_@(Evmz^2b; zO+~JY(>`Q+R}rmAsXg3N!G-;yuuAXX@63qM!;JzOG{2tgz6tf>xGYnsMliW6J~E`G zo&%&qB9jXL@H=DX%DMN(Un^Fvw+lE8Ky1I&Kife1) z*L=SRfQcWD(Eu)LBzDit-rLMh+OlGQz4+o`CI0q|UTpXRW^zCVrmtsuQ?NizkitrAni*XQ zR5g|}FHhZldFuDF!3W4wD;Uk=vl?Av0yHNh;L^%e<+dbag-!xgY`M2;&%d|KDo}?c zws1}8aQ|D<_k}N_zpw!R&mu6kIGtcX+b4*AAWZp&8gBm_J+FOZhwcGEY|c)7Sl1aa z$M|iT_JIQkEmC?MWahe~j>d-lj%)vcG@{;>`s?y~Ti@GoKiyjds$I=B)>sLDmGxDc zd{#gp9X0mI&lrsbuJ$WX+ELA2R`FQl$rm!}&6;xIvzUC>6z(d3!aba8^{LhC$|%s2 zEdYqo7Y4bR<^DCe+mNyZApY#hvX*2od_$L*41EG8OCSW1(8mh~_InvF&ojh6+}IlW z))RGe)X_L&EXRu0bw~cd)`AsGE%0%(-$(BVz~ipG0%#_Qzh=c2&Ox!3vh|Qj-+%`` z!>)|t2Y&c0;e-9&IxXwsWD4v z2@p`>MW-Vx0;aac!05zE)jRmx3@)1lqc-zp7E55{u1BWA-|2#g5UwM3u_GRf)dGK+ zpe<*s3#MQeyk{R82-oK+$xtr2vAzl@%9@kUZ5S`mx!aAour+a7R&EV8%s#x?rr!m) z7-pw1x*xvV32R*iZ1!Ja2KXJ28cf<-WvWfuqnpGKvA=yM|B0Gcs89HjHZF(ehv+YH zbO0m184_YXpRS)VK!m*(5JU&D#b^XEx-@{ggPyxnYg*&-k084H0ns&zuaVo;?3z0t z?KJa+3ZH#3DM2ofsAl$RfuRf7tY@EnTq9ZeS2j?ADm_FnW#H-_fLV~$ww>Z(YN(hJ z9pqkVN5(Bjsd?tI_b;Dw$+y?aAupP_+ zi1==emI4L#;xPD@i|qntTrjG#jqYp>6d2ZTUSc@W6nL(RA26^pZ(O8-?3Ee7DcS(} zePv*|0CjM1EAZa!ZqRbYtE2pegdqwYj!l&gRvEox4fyL06T>dsVkrQlGMC+!1cT+v z1S+rQp_{KWoGSimTI~>rUK031qm5bwY@vyf84S8$#b)*d&o85bgBNuIhFe_=QKmAL z=k>GOc;%MoIpHmb!1LS?+PvfIcEN&zE|G#8C?oc5`qE=|O+gZ&#hLwNpc=~uaF?nB zPCnu-=M`{&A(AX>Fb zR}{~Z^0#|jv6|)AUbKJxTBw|<(l4;`HIH{J>KSI2kMj<3LfJfq!l6ykrAQk~&i}|{ zZ4K~#`me`2e;=5mlqR$!Ha(k7i-CyOAY@cVE!|uGkPxCi#eGl;IY{7Km7T4+N^Alr zQ&*mOygJ;s+Hp`_mo#^CMoy4#X*C7LFKN4BKMU=f7u(flHQ%R%RUg^1Y!X1@x`{vMHhT9Q_aAFuE3 zu_>iJsedDA0`)6^+0+596|6lOCMK#{12W3O!;}H8Vz*c^9eu&C&s*o_NZ;^9^foB^CPTGyKGL^PO-IIWT|iHH)WuGsccxJobK7of zF`R}sUx-@*M50rVd63#E3urktWYD@k2v5Bl2dq#oivZ0V1VHC`BmE-{wiE6RxP?cS zLh3sR5*5b9rLztaVy|kHnCh&p&1Z5t&iEa6pm@TNy}f$_DXO`qM?G9nN(U+)y+sT7 zKz%06L0Fq5TszmoUwG7n?biJob5LJx(!stM8a;KkbYPDv-C-lxWVWN?#)rut0iA5x zHqmf;a}#(TLgOYW_TC(ZO?s+Rk|7TagYD#~Dhx%hj16&-V6%FmAoyS}G{?Bk5{q#I zw7b260O3y@B$a`iFnQt3kFddn8UUa7>Aor_JBv1+<; zi0V+Wem{4g_4=Y|6`J}Rcj5oT*muBVy}$2Al+m)HRFqAbMUoMcnH92?l+5gqnaD_G zWF<3XJ=uGe5t6-k_MVSD{`W^Ib6-On*4{D6}+G7^T%%ChIlE7LB(` z#HZe?RO&IagGl$;O%tdC69?CIrda@PrYg;u!29Lf~*no)2|=|D^@5-l?w4JV6VS{9?x@CY^x`=OV)g3afXIH!_d~f(?9C# zmoH!H73*AKLO7ZfG#T}CmSm{Np`d>m!{%qBs6fu~x@}FAg7_)HM?*JS6*t&9`i}(# zad*;5oitWbtN*4tMO}Xl!FehgiEqiIem1EH^@$5hI0`!@_rZJhlQcl zr8l-VGA|j)h8^UxoXzuxl)-2)0}%YBV_*KApB3nU{xM(6EHC_7aRTOWzNCD)>Nd3BKE*5LE6Uk~?)pG7(a)~6^pV-&03#6D(n$8uPh%A1+rlFB%> zf24ucpiLlzpMTwg^Fdg5gR?tl$>+sR=aMOyUR{8fv9>r+%~gC6&Eu~uX~VDwm%&I~Tmq%|?+AdcBlZUAY4iCK+d zv2R6b&Sa5h3hq^gu1YBW8YC|y-#Vc!bXcq{P9-B4!GLQFUV5v6f>Lv61hY+s9^hRP zA2u!sPIc79`<7@PkX2<}OiRhk5RX&*a3~os-ZB(WQzHuKf#+1-=x^^!?OWr*u9olz8o_ zyn32akA)ISjp$kak?R|;-0f37oo2=_ICFa;4*WHJ&P^ZpqSp%bjAvUlI=L55yC^T-f2fJG*E2btpT*z1VzFOk2l{MmV>Ih9CVK@XGugx+9r;ivwtt2 zv=MJfiXPwOGGDvbJpo9mR%bDRX&a;sFE*^_;-Z9rcvbLK>nEdE@KV{hCuT%t-?{a* zA!v-E4=!(!j9xGE6yC@WEa|Q<-5`b}w{un1^yRR<`L_n^9#1#(gEx$yK>@Jp2t&iK zVcQYvmhG!ZM{i7P$7nT92Ge5MTXE9uE!7R`r`8KSSpk|y94h0Y{Xx*KB$W0RGxSC4 zsuq2SWyvwc-z--i-B&%!CCxK+z9@Mx@FidHfUyI*`N5VkVLV&5Fe=mYWZHcl6k`<2 zVJ5}I+f5PkSB+|UmorQTdOp&Hy&WxR5!aN<-EXexux^;qxmXSF@d=gS6Y@d7mGt>I z=^+}j%7zT=qBc{*N=E-u^G2!t1|h|%EjAkHGSr&`t;X~Re1m-~G|Kn1`cuYZPCvL& zBVBpiMk;x{@(_)~j>jg$o0Wp@27p72&l?$$KF(GS5QJ{%0|6Ax_LE1fz8=%>;Y$}e$nQU#SpX#eFip_y^ccBLX5{6 z-@?~~m{vTd6L(6Vr&zA^-!SaZ?@90oU{;?rPGGm5f81Eh70kZx_^*QoLbu9%NbcW>Koy1M$XA2>X&FMiLYf+PmgCs~3CgQM%-V1TRrJ`R@G z*FI0yARNli8bm&4?jM6y1?>k~F zH(c-DijlOg|kI=P0vrvyaa9L7T=o8`j@qDeh>aZ&np$c#_+V5DHg)zBBoqk8aR##J%i= zYuqzF61l5}YszB)bXdyrl^yHZ6fq_V^75M0ERR#MkYEX-yS$aE^M~q_yX_S|3 z2ERl^j4eXQg7jqx8QS!qa>r?lq-xhC${wR{T?;$7?GnN`*Gu#SM2JF`WcI{~GCr7I zF9ZLtFiy&+M+G735CHkq({hH6htl#HKny(5&lU;A#1a}!G5R*MtyfHgD^VZ9^bBxqL8 zR)S-H=L&>)v~F++#zdcOWyzNF(q|I?FnD?ykKsaIQmJ30m%N|$$xByw{3fGXv9OC? zH3gQiM5Ny{yQbbOtvRlDD5)y4;hDzj;5d!KIDQ*Mm5l%!)h;Pz2{i`vUm`ffJxodI zQa@i*023n^JUFNGPGR2_`=L5Nsd?s0hkCq&V$vF?c_Dz)+%mgGx^vNL%}kK5y@8Tk zjL>uxZ92nWZq=J4+LZLgFmI;N>XWuU`1gJSeU=B5+SKw_s_XP3k4&0mqQkN*jT|y46|X4V3fx&(tcFgbhu!@^>8JnG|*KS`mMGAlCKNccoA6Ghw>x zoyGwj0MA*^yLpw3XKW}?`{rz?|13d1r^AgCiasVNG~Rn8EDO7?QIu~!TjHh)S>08; zZYyGYAwK`et4HUA%2DSt^b}0Dzm*OM$Sg`QRzj!NYB z6wIV{8j+t`!$d=Kn#u-yjfq<-QjsLX`VmU{SvgTS94d0P1f-nb2{9<^Kl@g2=W|iS zR2L^ZJG*J8zy3NX&=Pk9j9R2b91-i1A@m}jhJu)hLL-ax3c0d>KA|YUl588Rl9api z`2qN&G_<$_!SLwo2j}Mj(k?h$yUp5mD&AqP?3{yYCBqJq-=jGpO{p6<*=69Uk2Fno zu)aT|!c?8m%h{Kp{<$exbg}=Wb3$rvX6kug6I9W*y^b!P$_e_WV_7C&&bGU2KSMKD zEgZA5F_!O@u=Y=UsZ;&tp4~i>SElF1`1XsEI2vKl8M7J5o{q-31x+iEvEk~!t#aft zUy4rur^{ZqEAf+8%9dJ^* zwfcfatsT_MlcYiu!73vPZfOjKJvAg#Dpl~AhxHV5z1><4Z#}NxMM8t4g;iW_)8jldZ#O-0=5R@prDdy6UeZ%W zX;`@)3F8=4sNxN(|bqs9jPUoUo zv$e4i7Y!1BK-oYxB$q#5(XmqhJ!O$Lg92={ftgiUId4ar4=S~&1MYeVJ^pdU32z+| z)H9h03JJsUG5*#qN$b_UF>;KUZ?S%7n1Nu&r{0lc7>aMxjyk94SPKD|zWf_W``}gn1pY+JJIJ%rQ z^g+R5!jczls9O;)0|I(Am)C@0Xv|hBCvJ0=B~zntXs!)hH-b@>OT8 zsEHe~o_z1wLnqj)7V*!Q>_@M?J;Qq?(4M)q)~#dt^U;1`#ta7T58)A-U3F~OFRXfk z`e|gcx1dHFoUjJDh_KOC1?z_~=lVZDwKRJ|e?@WP@gH&4$Je^xdPcUH6_>N|zM;(sAaE+Y0>l+nZdV4VfI#J1xE#eCox_kp?`fTK;Xx(Q5iE7L*)H7|*`aYNjA- z-JQ&zNh$LT@0!aIFmuci6Q(?*EL#o9MO*Ah8l%QT*<5uxyK72CTWm&Yw};Xn zqE;#n5*clj%f;VH&VQzEp|Hfrb0z7C-)L&9Mn)1e#p%rpy5F!{UrJvY^2=E0wtCP; z6Yv(A0XbzuBI-8rIlC;BSXe%Yj^Je024AY_u^y?>l8+b{FU(mR_nZPrUpJrVi=uU^ zoh7}G8aemUW8{!N-;c9(C`MhU;GEDbDU~@dkO;8T%<5wwr71L@3f}Z2>Tsx}>Aod= zF0;pm+~JJMiRRuffD^C3Hxg=9`Ce%*_$buB^R~C>ATvwBYS((~loZoPualR)>hH8P zG}wVc&SzT5K-s>_Lw@Dcb(sFXv@h_{>i~++9}%wg@O;Vtj(i-Nsa)zTm5rzeG>kKv zTOt@X&`Ouj(x!9hQ*8xxm{upHs^BljhSv%iMQx##9+w4N*e|A*b6SY!7s>}t2Vz;r z&*!LQ&a!jdIfnxt%wl7Ri?>lz+(X??!zKXoC)f-@676n*t>zu1X%Z?`QRmz}z{U?gDG)#y#`L3T={^@~kz0+4Nrga+Swe)KG zRY5;^fqq>;5R!_?8_8Xs>g1|fyPN5t`(C*Ak(&q@(}7N+DW5W~bqJjXPyRK1C+ z6@O~L$=z$&e(9jo;(u=&0JCujj-Gd8wje??eYCD04+Qr*+D}V-JRa7jNf_H<(Hb0a z2kj9kBh=+;&uJ!gNpEsEK7w7jRUOsi02#&#q~a7YSK(#d1>EOhBTo~&nN^ph;xyU0 z-mq+!uLtp89!4l9z9f!NlQDBwpc|Qj7tKC)GLM;lc74kfn`=fpprM3%w~2TD#X8Ue zeE4!nF-fI=MxI?BdaR1n+r;f*g$!U9-N4~v$w9~dqT`@X-dBO-t7H*)6Q0#;Zempd ziN*s5acTLmI?;L&D=Z&}zgkxy{1w13c4@o1Y~h=}@tR=u=>&y4YU)D_v2X9Vow0F= zkHE3dA?SEr?dqcjr^G!66d}E{W`jBOmWJBf$U77sRr`6A;)RV)<<--ggzIS4$0a8IUx0%mArXSA{N7QX*N*(S_XI*LE)dbrlIJ6}%Ibv#H;(8uRZe)-)ex+KAU{kbF1 z+x(rT4BjUsJa0O9MWRoOe;g?Qag%5P4=hp=dW_j=Ky=e_bppj-u#~!?TmSvjDfir!}7<11*8u(GpL~Nc7CU9qN9QN}s1wB`oK^9#=K! zr--CJkrX+`RjTk^Y4CaH>5jzPDUn$=x*?naE*;(a@ksAVkvfyZ_=rf+S$F?FmSAGb z+jdqmZQ33k+gZJeBR0BVx}j8d^aa0h&t#qDBOwP=FGQoge!7>`vdn6Nd(|)1vKNh< ztuHBg5E-p_LEK!U199I?nTr>H#&eVixunqyQD&p*OZ0d?hR$OlR8J3L1-$5JmJ)bcs0t7H5)ll5QBI>4_In5u;KE{`MLtU<# zLI_uIOT>qXgz3JjQD*ynYwu(wOa^!Qwy_VfcY9)du21JYa8b8k&4^*~D=06%0sf;@ ztq=l3F{>@OgYPldT=c@KB-?3o{4*<1Sp`m_Q%@cBTE4_rcgxs8%pS6A4jcV&kl{lG&c9$ed20J> zl36|!#Tg09SLUSMIsk}2VyyI1B3e0hP{KhI=^mFqzv6kM#4dh&UgA5+_3@?;3ElP^ zYZK+dFNO9O5l77&dS|~zP$V5GE~^;33T3aU_W|W=pT|Z(sXk08?j=v(Pyk(^qP|6E z<@o{4ku-yLA2m1W@`9FSMwPMV(82cs?>K-PZ%S)*ZNhg$vraZo@saF@I3ILcp*X2= z0XjFqwdxb!(TJyMoJdnHl=~ilr&-$*?keDp|7dUTPJRe=&=hN3q0gX4!v|f)Gy9fL?xzsH zSs&no5N%2Gao4ZkHQnAkI&X_az@W6st+6;^Rn&V%QU96-TO4)4rR7DvVeagAOFZJ1TInW^XcKgImk|8k99j`Z~Qp-~Cr)*G62 zT##DL6XAV%bo^tY>uxT9_hLuh_EG+gqQnO)FA^7cbxK$;x=s9k*ZBbaEU%ST!9f)dNVTVC*ir}q{+lSOse0q@unJwI|O=?eX>q|SV}jtOIbF1W?#tD@8X&XVD1hN zl4?NxWf@lbpc3hEiBD#QBUr6<^^Ez^A4E?k?iBHKRDRFHHTg`mYl0TM83=SgyBYgENaIN4r^kZJ9`Pv0XIWu*}_!{DsWn=J)Ky@d(nJ!bX#o~@;uc8z*h zmwS7A4dlU1({G1UCFfza0k{QRn}?=Prhod@l{4eIWlu6>{b(R(-i<;rCtm3Qk#GJ1 zzTXAsolk^#)FYb7L`S5wiLoQE(%G%bfiD@s@@YO8<#P?}MWf%ST)|rMo7a>C!bNwY zT>|?8ROYnx-a=Q2(OMF#-3Ou~{-92zId@G?t~HTm)vs7KaIW>99c~;8dpFyfTyt}^ z?FZXfEZU^CR6_y>4hg1D*&{>z+wGiV(c-1;aO}sdql9B_J+8UcKv(IwXX5=n3Op^= zV?+u*5~=iG7}ghas-SA9P{;-@p7Ws*^eW)l^5rNHg2Q;Aq-<`ip?f} z@Yck8?13tmw~r{?>KOyUb+JPTS_$wRR(S<-MbE!0aN3RLIrg#KLGTL}qjgv(MUU2(s0PIM?HLYpn7RJtYH^DgPB~Ai3;8% z;~2(ec|9Bxl50DX59qAK>z?ukE3>u*E-&0D&I~SJ5FL77JkB!iurU`K_k{y01TJ-3 zP^=;AxY;5yROLU_rY$}1)~FwEUW622jq+0xLam4Em%7ZPSJxqJfL>T)h`qQ}(e)Um z`gmEqJl8m@+cK$0lVp?7W7>b5`3V08y%Jh{Q(eDv>CpN}SW&?gWPo~{oL;UB=2CfI z=KL72)2|69{*U^4AK>FXk-T$-F-IUl`oPQj@w4LLw{zxI zQLB)}ve5xx$hq3xhA=lZh@lw>biS8@24t3yJG%;o1&|LtlCrlRd#~iG5gV;UCo1PB9&GKr!sze8EdBLOP3L_Db(4AX_ByVmBB%|u;NLtA~gze2F{BF1?e7#ZA0TD z;&pYIvK|x&=&6anz2ch#KK2fsu@K>($?Fq}-DS75& z{qY(M`bmKc;Eh>#mS`4>wG^}@04~O8_yy`{w|+NMQfkzC3@0g9S6wXv!_68C0AeHp z8;x|K0o^i+X3w>&qqj**ikN^T^CW%N%ipmj=rA6Fb_oImu`S5u`+@S6fs>~FYCCAQ z+*dii66qP-23_xq(k3O?0c#eFKPTvz0>g$J|)5yp~dd1 z!p^=J#PPjz;HB9O^Ko;3hM-czgA(dt_T{%!pW%@xtjMO^ecajmTH(X34{``dVXoqX z0#iIA?(ipk9_0>zKf%@M$Y^?X0wRW|zW>c%Wb%g6rq zWQJSEN30+12M%EWgy45!US4WjrfUUpKQ@Pq8ix1JV*W{B;};&_W5>r57uIS9+f=O! z^nPA-D^nd7nZRYn*Hn%mxsNGh&_dJ4kGaFbLVAs8-ekuBty!*K+^vRB38-%=pF|dh zN8HM-CsRl_*!=1UJAyJITEBGJ&WJ+(+qKoW^f_Bg)(mAMBgvZE7WCdf*xbMNP??u& zD~M~xZaYKD=J2E0weLiyIM3X91CTB9PIR-$n?8QDe*Jers9tADB_ttrFpazJ$x;#b zj-FP83{u1#fEu#*7rS-3LF3gKb5}>o6hLA zUw@To`#9d}u!-AnZhJ1eY%62D5CW%0we|9u%QN{)5!#T4K7^_UIpH&U(u-GZPUFwX zMu}W7PB!(;nGPLCoGcsr?{4DY4hGV_t*f&Yp_8&{y_>?;vuQK_K}>mhR;tk~-2YJ% zOIBUNN86=*nu)D%^FEIe$Ck4fE})c}$4nu6v_2t*LvQQjvB(P8u@jw&VEP=rhe;A2x} zhu#Dh@4Qh1-dP*$x;t*CA3~Ar;WOnSYKT)17*veQnbRm?oEHJhCqCQ4iNIt0o@{d? zsWfo5XVj=t>VB?OJZWh`_OeQ_cpUH|6iANrfJ1YEib|*k`$*E4DC#pw<$kXT_&B4U z*M5eyfE4Oh!*yLW>5C+rhu9-~O0H0DZcs)l&4spVwh!_As?El@f)~jx0pAj`O#W!? zaC(=0BT5aE?crXSDSZGYC_LgZ1?O)?tPQ;6m&s_N;xK!P^oFz`ST~^0gB0lYaJDPr zda1TIPSuIiiOZOD`f+3F3WQ5y$4J?h@jE~}@4Va8)>~a6jr(rY3 z-N^L9eq+v-{Nku0a)9PdBx@`cZS(3O)ZGZ>L|&gW2ZH(Cpi%|mP?S6f2{#ee^)>^y zI$ZKOk?vY zz;w67)Re^&{=A7y1E$wY#1tJvn2^p{@B|&&U7WA3Vu<`~h;quu)@zE>fs*xoB(DUO z`!`l2gl(O%wfo2~v)+fyhVZ+n)@1bxquep0iS~v232-31vulTviw@n#C#zgB3Xg5k zxz$jQT}aJ4_RR~3e{MSB{-TPPMWEG;RzB7{gW~71Z*QC5tJvaiJTrPv5AfbSc-s8- zyG?Pu2i>`DKsL&MZ=k&3j*zR@ypP)AxF55+O$X9Dj8N8eJ8TnKg8Ot^k(i)1hBAHhN&>QUITAVDyEnBu7&83p?8%t2=xa^VFV{ z?9ZqE+5aX$45rBaySmQJ->a&Opzrn{S3vH(+y98=Ojzn2JrdN3ru~+WcQ$>l{K~N^PWFDdqh7cYXb5sPb=Zpcq(@ zEXU9%eD)EcdA|NZTnVp$cTRxfKVHiT2kO#9{UOy&KQE5FG5yxXzE$E|DYX_IVNP4+bz8c14W|;cYxXRD)(4Hyh3H*Ba6MRO@qyB6wJsI#l8Qfm>D;0Wl5hwmD-YIyz>T#CVyW z{vQpgFp|PDaDL(RG{s4aB}iiVYAwE;O+4WHHSgPPoWTp>MaD)$q%=j@{z3D69tD5R z!Uvk-=D)Ygu?t{b3A?2`UECbVV}8@D6)k|+8kMQ*?ksETF&qp8F9u1) ze(`F9rV~@~v%NNIXLloe?@kVExR|c4aowA@wpWrJTv{g=U(P2Upu)v;8pO*kg~y9a zF6Ee+IfLRAXTBKqtz;Zx zWl(WhcZ?!p&NSoqhGc7toK%rp!fF=133alOCkxsHk2V$lAuV80&zm>BY;)~cR-ALvh? zkaWQZkiJ`ISnd|0JnAgQ(xDjXDJaH**X(I?#CtEM4!XGes`eO_pHI1lIb`Tc zUF?^|qj6*;L741%Rtbp|NS?5PU`M|OI@14+-@b4=EKFIVy0j#jPoB2J3Q8fv@xr7u z`SA1|xVytZ`3Y0<4^`%!Tm6`?@Ka!><-LtK(b&M)h2Zi=L+!l+6+I9-~=ra;IEWC z^V8D(9;ZJKgL5o!pFv|bqVvxkefBxyvH?e3wzj`OxC_}cLVRNQn{L>|4R?WuIHN)G z^!3*xMr7X$PT{G$EvtoTlt5<&VF57sZ)wT=e{{rCRv`;$b(%fv6OPLoBdE_rV>|;j z%#uMUqM!$#jkhZ|6OjDWC?BjOLTcEQFLj@Y_|IQUO40;uj z%lZ}Be)ICBMh4U82*}{_mv|u7)hlWFs!$3t||E5JCAf zLSnzfZ~$GFlF?kHpDTGrNQGztt4BoRl8&S3D|1*aOR&vZ)Us`(ZDZNrk|hwa2V)WkT(zDskvHx3)1#EH0AU; z*W8cdq2;qZ6`WlJ#fX^I&OIY!Qp@J_XT}wJ?`_dv9{p9d*g8kf8?Qb0(KMrah`80u zu9RuX+*oGwFpFAsEF$$quWbA2+f{_5eLrzTzbAq6AKl?Y0&s+wKJpE^JC2uq?;zy+ zoy7O>Zr-pXcEI509k?Izw$aouQHb}F}aeB#{Y;}*NtVt4MvZ#w?NpL(7N zh@jjeEKCN*J|Akoi~WLP#CSAcz}n!`Xk|aDNRYgEoyII%#^*+)456qILD*Hfz^T5# zXWYzfT$e>6Z8n~CsXf)n_e^x|KOc$`A4!($WbWcMt*Cfe12jdy$H6aUU+lkb!_THn zu*-7_(2`fhF`4@X-%EUw86)Jl#i&fh*EIc!#-=pjBu5s#_Zgx;HqHTp^_kUOHz zdMD7*H`;?9q%Eequ12(a}YD;hjSmtTc5?mrAWuC5wto9SQBX# z?hcSZJ+|VLl$Lj6%QQ|HwflDd2)JL}ue}CL+S^oRuT3xw_B8f^`i-a~1OIYx5Qtdj z@9W&X403eI=sI~F`te*&={5&edXv&OdkqKp|5yy+$6y-}V={TD2SMA^?^!}VVUxsV zXu4VyWSx8MdZ3HzohrPallhYa%;dLI!nf%>?Du|O>;BMbC#=BvEiBf(7=6U;!(pwa z#<|tkd)7Dn%O1~V=eKF-i|gP~y&(u;sNf3w@Y|K~Y%)q?;~#nF(pibRdo<6ysMTg#@}y@^Na1~*GLQ@i1>N)tRQ_E$1DFI z--m|*?<*fdkO8*Y-O1k_D1lqpfjdk%zg!E%M*qAiF6-6(yI(~9{U7#X=O2H)(2xr9 zE_UldSARa0A05W<|E4(+um(n%nEW2=VT4}@2Jrs>%`+r(1eqE)u26;mD~#ctOaSuC zzsBd+^Zfo1sQWt22knzDoMubg0f+uN=#bTb$EyFw3PfzuPHd^=3kE2JlKv07?L?2q zO84*IM}Co&3d1!PK2!;ZYZUBu7LhRgMzJsErGPSSQ-V?j z54tM{Ki>y}ieCiKd!GFt^f^^1c;cbu9u70Cs$1djiZCS^Xp8;Eytujd4A75p@$=Y6 z_h$m^7^Jh{1WN1tW=Q{s zaZdhv|2-a=06e&;6XXHdiL^)p*`r2Ear`JS?*H$_2fI%LS+UzV`ye*O)5Ruxrs&wO zAWCD!LUsaq4Y|QN%ZWC?+t(au2U0f zAKt%t9=H!gF(n0$10hcMMeKA;N#In^moEolz=V>=e`MPn1qiS%{{g$)xxtS|qC{Te zF+nC=MG}c6C7j2)a#%p<)0Fh`PXagsLap7h%kQo7dp8Rp$Ns(p3b4pjomQv=LBgwD zBV?+F34}-y@C!ozfDe2XE?)n@j#~;Rz-esTqzb);r ztj1sw=9lgOeOGiG=+AyvdfJ~M%3zb0eSY_~!_BcS?^3(`vfjIA4`vQR8^&}PXf%Lj zSJXw!EwA*_j-TQ8Zr_9dn9(2GP87*bog)F<6y+51n|Z3`*i`>#@Q-YaQY4Fb@Du2M zM`!JGXC1$}7fYh$;0|4y*QgA^A{igvIIEy{roG@~l&1zZ=HAvL~R})^} zV&{R&5#i8&0+U|VnIIhaEp$EjTzNd}J6vE~c=Zlb?b6=8wlj%;IxN)3VUMNYCxP=| z0t)o>u19C|nF&M^ic2vQK9!2PidDoq>LVKGe_G7l-Sq3{lx}daaf|8-Pb<9A(Uf_BqYd9FuhEClMQ( z=;2WPakmC3$BDn)jo(K$RCq)kD|?@x+3_}!`zL(LzDJgX7xf4w>QVMsN{-uJG7vmG zzk+>Azs>gUr@d~Dz&m92D?i_a`%5EMU7R6(uU~2FuTY(^M-T!nJ!YN^Hh=twxV2}jZusLaq)6==l$~$KJ?F#M%+Mtgt zioAg57OZ3y_i!(}eY*T<|9&TDyt@Ch9PtIA;eO)ShIq`>FzJXE-XbBS(xUwD5MPm& zRdTCO+1>lUm#?s@WBXsDFvtw!JIy&M#)6T2+$o&|Qf24(PKXeB(A+*vdz?H${m-k& zoWTy{_?K-TF3LfT5hH4F3Tf%_^Fox8#a&HM;vSmFRkZV&Kiu0m@vApR^e9I1ZwSe* z0r=t3gnvYaOwnr#88QakY$cj9y3#oHfLEOpK26D+KOg7yaV^u`h4*U#|F+Ihh=4Ew z>o{^eIi(Ws%wIaYm*VsKDpouzDG+f6W@=62XUKdqh(0$F^urOBc0BRd*uVoo=K42T zr$7mE)j*;GSe;IOL`YV#k`)iqa9z(3$Bkglg^WvG{2#{VdGbDvJ^ll{?mR-Jsd?@S zV&l`(O=<&mC?Q-_o%0kE=lY%O}2z$0hrK24OZabQSamH9qdIjthWPBBHPXdd$o> z;AIq_o1EJNj$&Xb#{Tm;kXhLoly6rBCDh)@bzb*M5 zUVM zlMX%?K(qIm1Z22L?h;R{rARTA>ROP|l*V}(ihG#Y(f{qH(ZAVu@ON_KhlP;YhnPV} zzbf@?P7suDv+Ohkq~9=*wm-Pt9Ivo2@y#B~l%y`&|CEhZXn zMXx63we(@H80|jHXQX{Qsrz3?IkMN0@cR5aIBUul26VB+uTyexG!|}JJ}X!qKGewM zP`EbE1bi>*$s>x}fFvvXJ^(~Bm1wdT+a(7nI+{Khx4q>yD_D5=R`?)@eRNRR0=^~2 z9wwB%beO|+%>qG$Mv*U)*@xfXd1Kv`J~jS&hGi@ozh)k%h(_-3Vk45*>e z!bknFEombbJu3ya%P9b)Zv{4|vQDGc>ARp07dr_pcS|qjKe>OKDsK(swNcZD?tLJt zu??|$ky{8_3r0$sb}s-T_QJv7$Ox>L9v2|-p%IcYZ5xbDT zHty$ANq+^E+@CX2zWUjIeJYE4c%z)WadQ(CFcZxu+uF^O)blhDz0_WSlpM)h`R@I0 z_0?G+!{+#z??)H1{9Oj7rANLYlB-8Ap3rzya{b*yd$Frq0tE58G|1wCHHBEf^@|EL z1*M!xgue6)B0q{1PF+~K|1%1u_kgu@U3P#BOZ-|NOn6p^@wC2nxmO0vFh|9S=FG=) zKBuPi>O80!2dE0wnKBk9t&=XOWwRD0WNiX)r(?9fwhfxwKwXZ?-fMk2ulM)`m1uQt z!6~2_Y6hU#U2i*a`<(fzgaQ(6)5)%;k2YvMdBUo`l4V1^O6Kn+yi_-c2)Q*SbyPe)RzGlZ z#^TEK6JQxk0R&$Ih|a%1ZPk^M%zZ~0+NF60UkT-lw%w5*h8Q^y{SQuf!;cN$r0>dj| z`b}gO6K4znn^xR8(xEV(A&P(8#n*hPLtk3IVQ>-zp(8T2CJSvZ9PY1xJ!*)Y3d`|S zt#JbY6E14WG}PzWTolP1d1srg-t#v8R{N*ko44wp=+N?v#Mp~RT5rtJDM;BwFF2~; ziXd{rrSzg6Vk10N8Gl(XKfiqgf1Omsh%~9QYCT5=);YUNECm-Uotb<=qSFaMREVcGmmw6{-rAImu!+1$&S`){(?&n0y)t_+Nj}!QrNEYp z{L(l9?9Zp67K+-{U%rT5l$wc1+|32Jv;uC<&UUe$0Cr_FP{2)1mXo8hfVi(o;?&#~ zgEca?@2~3;yZ}D=s(D*be*U@l34Z&;Zo6f5XxnLR2T|UU8jHpV4K|y_?feG2rVsKJ z%z24vr)>=^*=1gw%(F4nvr6f;U(XTBpND|EO%I1YSRAF}7COmps*i6f?MV?f8Y)6lMf`c#pL z{1Awmq#AYS2A|@*G(?}SnNR~N8+14i(Wjv|jE6;C98pmd9{E~ zY+YURm!C$-i=D0aAKT37J5rZXyXJj^vJzp}Km6kH*!$CFQlD^W6J3rl7P}Ji0MM*| zxk=x3xMuxJ?@f{S7847CpG)ad5Umfuz6;r<1KdibF~MWJ6%{MRqKMK!UME0_WxV1b z#gk)K(uLe4B$?`6PU5FP(?=fNqzch*&6Gkj;AtxaH|FoQw;V$6v;`5{{v7*bDhE z8FpqKdGQ$R6SU;GNiw~6u_QLp20UImqy^S*pj6PInnxAwfgHxO>ilHbJfJEM8a9{hGb8LC#m#)wFNpM2Zf?!_ue5TO&D0v(R{9ukFz3x^AQycP3yy~Eymm0j7Xe&0=5%oo z{9}h#$Zoz%NK;17Mq4hA0`E_CT7CQ=-&=S8b(Bhm-d0Kpi5fylZUq!1 zFDUp+dQnxtKJf5@DreS0t+76cTPevm+#PGs*}Ba$`SGb{tQ;Sf-{N&vcH6;ts`V2uy4Zl)VluwRgJq_GtFxDH{tJ~sQ{0V2 zFt$@Z63m(S%)0skn&2dad3k754wfqy*kmNgz0r31L|rzRrGli+PD!x;DiA~K2HAhW ze?)!Y&=+&QM~3A?^AXPMb)h7+oGMg+xegp(X&`=kFQrWgAoQ`WH=(!vrCTO`TFTur zydv8dCoko%0sW0WOX21Egb8g38nSu{jFF|TpY|ofWZ}wVP~n}ma#*O5E4qp86fO`M z9q62R95UN%NyJg3T{*@rz3)>r=uK!Z^Zk5MJSKrZtBkvD?hg*;u zhQ#L+sGEUki&`h(s?+q!))%T-5*AK{D<*YsY$hlsrGko8LvM^Tl1GthP5~sqhi#y}_nrz@LJ;8q_Zhz@mKzsnt{Cz+R%ZCMIOEQF>dY{=WsF^G2)!8R>+V{%-Enix>~>wtwfU%)X<+@Ru?4lw zm7eq>DKkFi6FyDnAi5(CxMyrOyDB~(tvCw|Dtba#?YvwP!6$7gGB7j3jp&c zg8`RO7h}Uin_Pysau#C~_m-t-DtG>EWPZ^UnP=*w>!DgXlj6AAa- zj`W8S+Rb;slZ6A_7D!(_)5pq?vlZCOOt9aCT6R?Gn^DNe$L_@1y z-nyx!>L88>&wNzVq3yUMvxc)XZXEPCS#B>+E4720Z9Q<&xTk8kRyL?g6q{6>)`ysYyW+M=im(_H zquJ#7d!Heglyaw={s_@Vn66(6DWbuMm5sVb ziRDB03ixBBg5Mf0cXPG*VfpCZn<^TO#NSj`;V$pRxdra?ps@m^dO_YwrTM_2Q3`R^ zIV+?1bc6O!(?t%?fjIfHwGN1J#i=g$$(-|S4MfWp*jVUyq>Hu8Ew_VI+UsV*t+ZxE zRp28Rni`GTChvKj@jf~v(@+(H#@>g#wi>6$(`?WvW!_H?7t29#D|q%w)53DEgHpen zMu>SWuT>{afSQ4L-JBH`W2Zsd3*fp~U22k-UO^ef%beZd4`C*v8oI5!%%;8TtY}-~r6S;e$_IgON z$;L{G@&NB$^;~myQ1V(U4-ikx0ax1KYv8udY1^!T*(mL>C-ZFJhvQ3D@_^98MYQa> zs_<+3lkR+$A8?z?gf!fU`se2aM>|8Udis;DEKH_F8O{#|BpP;3wz615 z_4&MeR}Qv00KJD=#T!pWEAGjULInyBz^3a%==LR}s8cq_RHqXt3?^R*9br4I z`M&D7ky4eP8V=?vE-@V&1mOeVaI*pG(fceLEx+~BpAlyzkrwrzQG-(?l9n{*@jkDP z@olGHP6o@#nYtXQpEcDUMn#i?&j`sQu;k+@ZMWs)UQS3OBwxElB|>a6ynnc2kt{Oj zkkq>H?Gwa1|LD|oT;>yUKGu{$6#*$Q$H;+i+EiO3jCj;!@{sL>6SG-6gi!ldd>D`G zZcf$XTrr{={`-c=r=KbFN~BWP9_jU?UqIj_K7D@~O5u3k3iB6LjH21y?mabpqSTlu8C>4v5eFfudf51#$9BIjm?^XffYj zJdEWx8`%s9RY2sHk~KfAWHY)_QW{8>P=5LNuZVBw2I2X5tj2##V0asnN(p&|0dO0q zrjrhcBk9Sk_h711bFd89PhP2zegUMsKot(Giipyk^O!73rkkcb?iRmQ|9Sn96T7*9 zl0n3E*?GOY+MviW(wV4yKg>S2;k4l18OOp31f}c0=7jhLB`3tpAt5W~cPh#rk1LZkIG*NIJG}KIy^`Apifh8U5Lh7UK ze6DHFo711gaQ(Z&ONooTK1K?)o7Ut!&8ydUM1&iQSD>6HCr8Q0O&drSC43^_a+G}u z?x6oEvsQJMc32ohwCB?Sdh(dy>YHDfzE`4-oPVrNWYO+q&JpEl@s@yk0(!sVBRm@q zh0PD+p;?hSWYsO0E4+YxQTGC!X)B(rjp2oGH%_jOklqGx%>Se7y5qTQzkfVbM#)Ml zku94dBUEH%6eY>XNEEX7YKW9QGqXp?&its1>?GNH@4eUW+#e%7-{<#FFR#>n-`Ba$ zd7t-L*Hx6Dj*4Z6isnN~E1ab7)Sf5Y-=X(%pB!zT|5=HB1?EVYaD5o8H zzym$li$7c?w3>2%?1ato;X`6z>(3vDWB>T_Q#{P}OM@iJ32oI1q zi426a9M(Z@2Bad#d<%7*h66FhE948A!Gaxd zNQ+#mHlWOP+XVa6&WMAv30>q%GU(I>aFf@33;porpXJqGN53Q!d)k=n4}Yt4A@7F; z^7AjbUXR#)vUyv?N&3GsY<^Yvl1@ydk7V~7d`MJbN2T5xe|UKc-lJ&g#(ANM*NUF5 zuoSbB6Rq$7%$F9Aos&i%{S=vnb(vsSntvpZWKaV9MT%?|3l-`C8kkq1B8kJ%P?TG< z7y4Jhz=YZZ&9_o$kM|+}8sN<0oy#ZTMLcvB32)^*8Z4l?K{A&7tl~Dcml?+4{l)AF z{=k)YQphk8QK`=3J;jRTz^t4~)+R$lk5n7^ZhXim(t41PR&bcEfKfAqNE?Kuv3QC> z^siljtq^Izy8Oo}MrtE9IC7;MXtQH{e@GnNa|mN1Zk%jTK>$o1W8=ILyLOnJHRx>rJV2tETl;qTp*Bm@698iVf&^yTu-_=j@_8KAE8TV!SgHugsj z^1-MAeYy%p&5!5$CH6tZ84L5`-%mrnn+y9kbeIHlYwveF9deEVx4QGC3SI-JR3$jz zYEQ2Ftn@4TbjVlUP(+H`e~Q=#EeGB3;fLfrVzFxV_GLat?WJV$)<@fqrT?zSt;DUm z8{j`wt8C1NWx> zN&Ug!**?&rn zbA+%E*e!_r5O+z+#s?ZvaNd6+%GE&1>lRYANB)|VNc$}Leyfi>7v|f4cgKm~9EHbY zCX|u;X#El88~RAlWN8pLC`JV%oLLE2QjBW}hQg?6P5T{fF^cMzEW6KsMH>0nC@p#c zXq!Z=Fm}AQ^?(5XOFrE_u@`#ja+qKlcikJRAP-4Fa}`l(=MAiu|F;ENBoUE~{;$xZ z`1hVP6jrYse$k_=*PBoj?4LTcYXkYi5w& zUBwzfkF$GiVMVeCykR?VAAmG5K za)a%_pse$ET*g+hUi3GDZNRo8Xu5S=6zpWjVcmpoJDCsp)F;n`WIJjlpajBq^xBz( zsOR>do!R{f3`mFTI&_}C4D&res=T25j-VT&bLhA1=o}%8^|^XeAz%ULitpaGy1yL& zM7u37S%@(j7}p&b*M*)u_|MNOIWPF1h#ml31FQKg?`U}%w9G`>%Q*Rasgx-;x#i!7 zP@%2)get}(bohbvV}lO7X$jqj(4)BW;#A7Wh$JH?3^{26W0F@z#FOMWv++Osb_nyY zD98CHG|k4Dh4P^rH$^ltcB)2FR}rHQJR1#h2;}DyQo$MGEfT2RzeS{NcJmqj0TwWL z*U9amVjRMxL;8>0h)pq}<3MBIPULeAeq#T%cCUya0zkD|YKUEUo_PCx8XC2UVQAv=^jst(?1H1!ma%s;F!v+9O zd`AEe`D#@%I>I*6LBQ^LyjW0 z^8u7^PZ07Z$i{kn&o!S${o)e2j27;NWhRt!84tit}6D+@p9h|yx>laoq(ie%?DFCUvwAXn_dcI}P zTPIxe56%DGriF+dno+-HAgwr0H~IcLeAUlK2O~i}gG{Y-(CCJ+kfZe9 z9}Aoeq$NHZeYQDxpV9AqBB{DC6xkvs6Ph$V^oQANAT`55DHUGV21cDJqd@i5lfYitwIKl+UHfTkw_Zg_>Ju_PBLq&MT$8x-$|L;;Y9i#(Xxf`SIk1zgp&p&A|7vLmfeL}-Sl2|^<{VQ1fuQ!nTpaRt05&m;B zu%;C(awt|4YiChtkp@$p*{^>gF(2q)Ay&(7Vul>SbC;FSy#ofS0uP~Qnxv%Byb2f_ zgd&Jh!e#(l{i+&Gq)ozk*V~x(V0C~*!s)>A8ahZ~rS-GvU3k~Qq=*E@zlHu8Opu@6 zYSoQMJ4^qjL-O~L&pns-B4R2N%$t9x2J+>M<_Kp93nf0_C}EEi+0p#TYllDW5$mtD zvTkf|R_oaKu$>`eU>&&Ish*Fi<9mo$Rc_ba?Ly5_zcUD^p#2-k z7c6pv0_3}I^m^@TV=}<*SEN}Bk=-FrXb%?&et*~V*M0U>?=c6h z?@F27LgWEdY5+{#Od&%W+R)Lp1~guslH|I|bHMYVl_!?5WT%lD`WwMOQAZx^&-|S* z#~4C3dEi1M7CEwepbmbF(FO<(Y?2zvBPvN-d70>75(~`SbYHeQ2;B~zGex3$01}## zo4aNV=YYU{VLL=(M>nKF_F5!Up+JU7=p@VEU4^J?TX$NhXDFen%roL8{n0m0W|-7b zBzaPB>Y4X@YU)DyhHW2pm4*)2U5IqT#AW>Jk52X;!KC@ z!kPd24Q>qyRl_SPKKkb`Pdö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�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

5LbU=~9tIQo(1~?N^Gccn?w$)2ZhMcsH3EF7|ri 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�z1vT@p{@=zp7+`%$=DOuyzuw9HO%UA9#(el!Ry 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 a)gPVIdCz8TR&Hj2KN>2!%DIXbe*Xhh5J?yS From 72e8f09c078ee04be660cb88510f78eb4415513f Mon Sep 17 00:00:00 2001 From: lydiavilchez <114735608+lydiavilchez@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:05:15 +0200 Subject: [PATCH 04/36] feat(googleworkspace): add directory check for CIS 1.1.3 - super admin only admin roles (#10488) Co-authored-by: Daniel Barranquero --- .../googleworkspace/authentication.mdx | 9 +- .../getting-started-googleworkspace.mdx | 2 +- prowler/CHANGELOG.md | 1 + .../cis_1.3_googleworkspace.json | 4 +- .../googleworkspace_provider.py | 1 + .../services/directory/directory_service.py | 118 ++++- .../__init__.py | 0 ...super_admin_only_admin_roles.metadata.json | 39 ++ .../directory_super_admin_only_admin_roles.py | 60 +++ .../googleworkspace_fixtures.py | 33 ++ .../directory/directory_service_test.py | 235 +++++++++ ...ctory_super_admin_only_admin_roles_test.py | 446 ++++++++++++++++++ 12 files changed, 930 insertions(+), 18 deletions(-) create mode 100644 prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/__init__.py create mode 100644 prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.metadata.json create mode 100644 prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.py create mode 100644 tests/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles_test.py diff --git a/docs/user-guide/providers/googleworkspace/authentication.mdx b/docs/user-guide/providers/googleworkspace/authentication.mdx index d8812fa7b3..e5c3527f89 100644 --- a/docs/user-guide/providers/googleworkspace/authentication.mdx +++ b/docs/user-guide/providers/googleworkspace/authentication.mdx @@ -17,6 +17,7 @@ Prowler requests the following read-only OAuth 2.0 scopes from the Google Worksp | `https://www.googleapis.com/auth/admin.directory.user.readonly` | Read access to user accounts and their admin status | | `https://www.googleapis.com/auth/admin.directory.domain.readonly` | Read access to domain information | | `https://www.googleapis.com/auth/admin.directory.customer.readonly` | Read access to customer information (Customer ID) | +| `https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly` | Read access to admin roles and role assignments | The delegated user must be a **super administrator** in your Google Workspace organization. Using a non-admin account will result in permission errors when accessing the Admin SDK. @@ -73,7 +74,7 @@ This JSON key grants access to your Google Workspace organization. Never commit 6. In the **OAuth scopes** field, enter the following scopes as a comma-separated list: ``` -https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly +https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly,https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly ``` 7. Click **Authorize** @@ -114,7 +115,7 @@ The delegated user must be provided via the `GOOGLEWORKSPACE_DELEGATED_USER` env - **Use environment variables** โ€” Never hardcode credentials in scripts or commands - **Use a dedicated Service Account** โ€” Create one specifically for Prowler, separate from other integrations -- **Use read-only scopes** โ€” Prowler only requires the three read-only scopes listed above +- **Use read-only scopes** โ€” Prowler only requires the read-only scopes listed above - **Restrict key access** โ€” Set file permissions to `600` on the JSON key file - **Rotate keys regularly** โ€” Delete and regenerate the JSON key periodically - **Use a least-privilege super admin** โ€” Consider using a dedicated super admin account for Prowler's delegated user rather than a personal admin account @@ -151,7 +152,7 @@ python3 -c "import json; json.load(open('/path/to/key.json'))" && echo "Valid JS The Service Account cannot impersonate the delegated user. This usually means Domain-Wide Delegation has not been configured, or the OAuth scopes are incorrect. Verify: - The Service Account Client ID is correctly entered in the Admin Console -- All three required OAuth scopes are included +- All required OAuth scopes are included - The delegated user is a super administrator ### Permission Denied on Admin SDK Calls @@ -159,5 +160,5 @@ The Service Account cannot impersonate the delegated user. This usually means Do If Prowler connects but returns empty results or permission errors for specific API calls: - Confirm Domain-Wide Delegation is fully propagated (wait a few minutes after setup) -- Verify all three scopes are authorized in the Admin Console +- Verify all scopes are authorized in the Admin Console - Ensure the delegated user is an active super administrator diff --git a/docs/user-guide/providers/googleworkspace/getting-started-googleworkspace.mdx b/docs/user-guide/providers/googleworkspace/getting-started-googleworkspace.mdx index 361de533e1..af09ab75c3 100644 --- a/docs/user-guide/providers/googleworkspace/getting-started-googleworkspace.mdx +++ b/docs/user-guide/providers/googleworkspace/getting-started-googleworkspace.mdx @@ -78,7 +78,7 @@ The Service Account JSON is the full content of the key file downloaded when cre ![Check Connection](/images/providers/googleworkspace-check-connection.png) -If the connection test fails, verify that Domain-Wide Delegation is properly configured and that all three OAuth scopes are authorized. It may take a few minutes for delegation changes to propagate. See the [Troubleshooting](/user-guide/providers/googleworkspace/authentication#troubleshooting) section for common errors. +If the connection test fails, verify that Domain-Wide Delegation is properly configured and that all required OAuth scopes are authorized. It may take a few minutes for delegation changes to propagate. See the [Troubleshooting](/user-guide/providers/googleworkspace/authentication#troubleshooting) section for common errors. ### Step 5: Launch the Scan diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 37b00bc5bd..f483ce9d56 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `glue_etl_jobs_no_secrets_in_arguments` check for plaintext secrets in AWS Glue ETL job arguments [(#10368)](https://github.com/prowler-cloud/prowler/pull/10368) - `awslambda_function_no_dead_letter_queue`, `awslambda_function_using_cross_account_layers`, and `awslambda_function_env_vars_not_encrypted_with_cmk` checks for AWS Lambda [(#10381)](https://github.com/prowler-cloud/prowler/pull/10381) - `entra_conditional_access_policy_mdm_compliant_device_required` check for M365 provider [(#10220)](https://github.com/prowler-cloud/prowler/pull/10220) +- `directory_super_admin_only_admin_roles` check for Google Workspace provider [(#10488)](https://github.com/prowler-cloud/prowler/pull/10488) - `ec2_securitygroup_allow_ingress_from_internet_to_any_port_from_ip` check for AWS provider using `ipaddress.is_global` for accurate public IP detection [(#10335)](https://github.com/prowler-cloud/prowler/pull/10335) - `entra_conditional_access_policy_block_o365_elevated_insider_risk` check for M365 provider [(#10232)](https://github.com/prowler-cloud/prowler/pull/10232) - `--resource-group` and `--list-resource-groups` CLI flags to filter checks by resource group across all providers [(#10479)](https://github.com/prowler-cloud/prowler/pull/10479) diff --git a/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json b/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json index fa32397826..7792bba0da 100644 --- a/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json +++ b/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json @@ -54,7 +54,9 @@ { "Id": "1.1.3", "Description": "Ensure super admin accounts are used only for super admin activities", - "Checks": [], + "Checks": [ + "directory_super_admin_only_admin_roles" + ], "Attributes": [ { "Section": "1 Directory", diff --git a/prowler/providers/googleworkspace/googleworkspace_provider.py b/prowler/providers/googleworkspace/googleworkspace_provider.py index 83beee0d3e..549831a2fb 100644 --- a/prowler/providers/googleworkspace/googleworkspace_provider.py +++ b/prowler/providers/googleworkspace/googleworkspace_provider.py @@ -64,6 +64,7 @@ class GoogleworkspaceProvider(Provider): "https://www.googleapis.com/auth/admin.directory.user.readonly", "https://www.googleapis.com/auth/admin.directory.domain.readonly", "https://www.googleapis.com/auth/admin.directory.customer.readonly", + "https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly", ] def __init__( diff --git a/prowler/providers/googleworkspace/services/directory/directory_service.py b/prowler/providers/googleworkspace/services/directory/directory_service.py index ef0b54c18c..6afa8e4521 100644 --- a/prowler/providers/googleworkspace/services/directory/directory_service.py +++ b/prowler/providers/googleworkspace/services/directory/directory_service.py @@ -8,23 +8,21 @@ class Directory(GoogleWorkspaceService): def __init__(self, provider): super().__init__(provider) + self._service = self._build_service("admin", "directory_v1") self.users = self._list_users() + self._roles = self._list_roles() + self._populate_role_assignments() def _list_users(self): logger.info("Directory - Listing Users...") users = {} try: - # Build the Admin SDK Directory service - service = self._build_service("admin", "directory_v1") - - if not service: + if not self._service: logger.error("Failed to build Directory service") return users - # Fetch users using the Directory API - # Reference: https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/list - request = service.users().list( + request = self._service.users().list( customer=self.provider.identity.customer_id, maxResults=500, # Max allowed by API orderBy="email", @@ -38,14 +36,11 @@ class Directory(GoogleWorkspaceService): user = User( id=user_data.get("id"), email=user_data.get("primaryEmail"), - is_admin=user_data.get("isAdmin", False), ) users[user.id] = user - logger.debug( - f"Processed user: {user.email} (Admin: {user.is_admin})" - ) + logger.debug(f"Processed user: {user.email}") - request = service.users().list_next(request, response) + request = self._service.users().list_next(request, response) except Exception as error: self._handle_api_error( @@ -62,9 +57,108 @@ class Directory(GoogleWorkspaceService): return users + def _list_roles(self): + logger.info("Directory - Listing Roles...") + roles = {} + + try: + if not self._service: + return roles + + request = self._service.roles().list( + customer=self.provider.identity.customer_id, + ) + + while request is not None: + try: + response = request.execute() + + for role_data in response.get("items", []): + role_id = str(role_data.get("roleId", "")) + role_name = role_data.get("roleName", "") + if role_id and role_name: + roles[role_id] = Role( + id=role_id, + name=role_name, + description=role_data.get("roleDescription", ""), + is_super_admin_role=role_data.get( + "isSuperAdminRole", False + ), + ) + + request = self._service.roles().list_next(request, response) + + except Exception as error: + self._handle_api_error( + error, + "listing roles", + self.provider.identity.customer_id, + ) + break + + logger.info(f"Found {len(roles)} roles in the domain") + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + return roles + + def _populate_role_assignments(self): + logger.info("Directory - Fetching Role Assignments...") + + if not self._service: + return + + try: + request = self._service.roleAssignments().list( + customer=self.provider.identity.customer_id, + ) + + while request is not None: + try: + response = request.execute() + + for assignment in response.get("items", []): + user_id = str(assignment.get("assignedTo", "")) + role_id = str(assignment.get("roleId", "")) + user = self.users.get(user_id) + role = self._roles.get(role_id) + if user and role: + user.role_assignments.append(role) + if role.is_super_admin_role: + user.is_admin = True + + request = self._service.roleAssignments().list_next( + request, response + ) + + except Exception as error: + self._handle_api_error( + error, + "listing role assignments", + self.provider.identity.customer_id, + ) + break + + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + +class Role(BaseModel): + + id: str + name: str + description: str = "" + is_super_admin_role: bool = False + class User(BaseModel): id: str email: str is_admin: bool = False + role_assignments: list[Role] = [] diff --git a/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/__init__.py b/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.metadata.json b/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.metadata.json new file mode 100644 index 0000000000..0264078982 --- /dev/null +++ b/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.metadata.json @@ -0,0 +1,39 @@ +{ + "Provider": "googleworkspace", + "CheckID": "directory_super_admin_only_admin_roles", + "CheckTitle": "All super admin accounts are used only for super admin activities", + "CheckType": [], + "ServiceName": "directory", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "NotDefined", + "ResourceGroup": "IAM", + "Description": "Super admin accounts do not also hold **additional admin roles** such as Groups Admin, User Management Admin, etc. Each super administrator has a separate, non-admin account for daily activities, following the **principle of least privilege**.", + "Risk": "A super admin account that also holds additional admin roles increases the **attack surface** for phishing and credential theft. Compromising a single dual-role account grants full administrative access, bypassing **separation of duties** and enabling unauthorized changes to users, billing, and security settings.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://knowledge.workspace.google.com/admin/users/prebuilt-administrator-roles", + "https://support.google.com/a/answer/9011373" + ], + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Directory** > **Users**\n3. Click on the super admin user who also has additional admin roles\n4. Click **Admin roles and privileges**\n5. Remove the additional admin roles from the super admin account\n6. Create a separate account for daily admin tasks", + "Terraform": "" + }, + "Recommendation": { + "Text": "Apply the principle of separation of duties by maintaining dedicated super admin accounts exclusively for privileged tasks. Daily administrative activities should be performed from separate accounts with only the delegated roles required.", + "Url": "https://hub.prowler.com/check/directory_super_admin_only_admin_roles" + } + }, + "Categories": [ + "identity-access" + ], + "DependsOn": [], + "RelatedTo": [ + "directory_super_admin_count" + ], + "Notes": "" +} diff --git a/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.py b/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.py new file mode 100644 index 0000000000..702e3445ce --- /dev/null +++ b/prowler/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles.py @@ -0,0 +1,60 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGoogleWorkspace +from prowler.providers.googleworkspace.services.directory.directory_client import ( + directory_client, +) + + +class directory_super_admin_only_admin_roles(Check): + """Check that super admin accounts are used only for super admin activities + + This check verifies that no super admin user has additional admin roles assigned + beyond the Super Admin role. Super admins should have separate accounts for daily + activities to follow least privilege. + """ + + def execute(self) -> List[CheckReportGoogleWorkspace]: + findings = [] + + if directory_client.users: + dual_role_admins = {} + for user in directory_client.users.values(): + if user.is_admin: + extra_roles = [ + r.description or r.name + for r in user.role_assignments + if not r.is_super_admin_role + ] + if extra_roles: + dual_role_admins[user.email] = extra_roles + + report = CheckReportGoogleWorkspace( + metadata=self.metadata(), + resource=directory_client.provider.identity, + resource_name=directory_client.provider.identity.domain, + resource_id=directory_client.provider.identity.customer_id, + customer_id=directory_client.provider.identity.customer_id, + location="global", + ) + + if dual_role_admins: + details = ", ".join( + f"{email} ({', '.join(roles)})" + for email, roles in dual_role_admins.items() + ) + report.status = "FAIL" + report.status_extended = ( + f"Super admin accounts also holding additional admin roles: {details}. " + f"Super admin accounts should be used only for super admin activities." + ) + else: + report.status = "PASS" + report.status_extended = ( + f"All super admin accounts in domain {directory_client.provider.identity.domain} " + f"are used only for super admin activities." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/googleworkspace/googleworkspace_fixtures.py b/tests/providers/googleworkspace/googleworkspace_fixtures.py index c823c21339..792c4699c3 100644 --- a/tests/providers/googleworkspace/googleworkspace_fixtures.py +++ b/tests/providers/googleworkspace/googleworkspace_fixtures.py @@ -43,6 +43,39 @@ USER_3 = { } +# Role data for Directory API role tests +SUPER_ADMIN_ROLE_ID = "13801188331880449" +SEED_ADMIN_ROLE_ID = "13801188331880451" +GROUPS_ADMIN_ROLE_ID = "13801188331880450" + +ROLE_SUPER_ADMIN = { + "roleId": SUPER_ADMIN_ROLE_ID, + "roleName": "Super Admin", + "roleDescription": "Super Admin", + "isSystemRole": True, + "isSuperAdminRole": True, +} + +# Google automatically assigns _SEED_ADMIN_ROLE to the first account that +# created the domain. It is a super-admin-capable system role with a +# different name, so it must also be excluded when counting "extra" roles. +ROLE_SEED_ADMIN = { + "roleId": SEED_ADMIN_ROLE_ID, + "roleName": "_SEED_ADMIN_ROLE", + "roleDescription": "Super Admin", + "isSystemRole": True, + "isSuperAdminRole": True, +} + +ROLE_GROUPS_ADMIN = { + "roleId": GROUPS_ADMIN_ROLE_ID, + "roleName": "_GROUPS_ADMIN_ROLE", + "roleDescription": "Groups Administrator", + "isSystemRole": True, + "isSuperAdminRole": False, +} + + def set_mocked_googleworkspace_provider( identity: GoogleWorkspaceIdentityInfo = GoogleWorkspaceIdentityInfo( domain=DOMAIN, diff --git a/tests/providers/googleworkspace/services/directory/directory_service_test.py b/tests/providers/googleworkspace/services/directory/directory_service_test.py index 83c7e594c0..50fc8e00bd 100644 --- a/tests/providers/googleworkspace/services/directory/directory_service_test.py +++ b/tests/providers/googleworkspace/services/directory/directory_service_test.py @@ -1,6 +1,12 @@ from unittest.mock import MagicMock, patch from tests.providers.googleworkspace.googleworkspace_fixtures import ( + GROUPS_ADMIN_ROLE_ID, + ROLE_GROUPS_ADMIN, + ROLE_SEED_ADMIN, + ROLE_SUPER_ADMIN, + SEED_ADMIN_ROLE_ID, + SUPER_ADMIN_ROLE_ID, USER_1, USER_2, USER_3, @@ -25,6 +31,24 @@ class TestDirectoryService: mock_service.users().list.return_value = mock_users_list mock_service.users().list_next.return_value = None + # Mock roles response + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = { + "items": [ROLE_SUPER_ADMIN, ROLE_GROUPS_ADMIN] + } + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = { + "items": [ + {"assignedTo": "user1-id", "roleId": SUPER_ADMIN_ROLE_ID}, + {"assignedTo": "user2-id", "roleId": SUPER_ADMIN_ROLE_ID}, + ] + } + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + with ( patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -67,6 +91,17 @@ class TestDirectoryService: mock_service.users().list.return_value = mock_users_list mock_service.users().list_next.return_value = None + # Mock roles response + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = {"items": []} + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = {"items": []} + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + with ( patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -97,6 +132,16 @@ class TestDirectoryService: mock_service = MagicMock() mock_service.users().list.side_effect = Exception("API Error") + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = {"items": []} + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = {"items": []} + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + with ( patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -130,3 +175,193 @@ class TestDirectoryService: assert user.id == "test-id" assert user.email == "test@test-company.com" assert user.is_admin is True + assert user.role_assignments == [] + + def test_directory_list_roles(self): + """Test that _list_roles correctly builds a roleId-to-roleName mapping""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + + # Mock empty users + mock_users_list = MagicMock() + mock_users_list.execute.return_value = {"users": []} + mock_service.users().list.return_value = mock_users_list + mock_service.users().list_next.return_value = None + + # Mock roles response + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = { + "items": [ROLE_SUPER_ADMIN, ROLE_GROUPS_ADMIN] + } + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = {"items": []} + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.directory.directory_service import ( + Directory, + ) + + directory = Directory(mock_provider) + + super_admin_role = directory._roles[SUPER_ADMIN_ROLE_ID] + assert super_admin_role.name == "Super Admin" + assert super_admin_role.description == "Super Admin" + assert super_admin_role.is_super_admin_role is True + + groups_admin_role = directory._roles[GROUPS_ADMIN_ROLE_ID] + assert groups_admin_role.name == "_GROUPS_ADMIN_ROLE" + assert groups_admin_role.description == "Groups Administrator" + assert groups_admin_role.is_super_admin_role is False + + def test_directory_role_assignments_populated(self): + """Test that role assignments are fetched and resolved for super admins""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + + # Mock users - one super admin + mock_users_list = MagicMock() + mock_users_list.execute.return_value = {"users": [USER_1]} + mock_service.users().list.return_value = mock_users_list + mock_service.users().list_next.return_value = None + + # Mock roles + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = { + "items": [ROLE_SUPER_ADMIN, ROLE_GROUPS_ADMIN] + } + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = { + "items": [ + {"assignedTo": "user1-id", "roleId": SUPER_ADMIN_ROLE_ID}, + {"assignedTo": "user1-id", "roleId": GROUPS_ADMIN_ROLE_ID}, + ] + } + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.directory.directory_service import ( + Directory, + ) + + directory = Directory(mock_provider) + + user = directory.users["user1-id"] + role_names = [r.name for r in user.role_assignments] + role_descriptions = [r.description for r in user.role_assignments] + assert "Super Admin" in role_names + assert "_GROUPS_ADMIN_ROLE" in role_names + assert "Groups Administrator" in role_descriptions + assert len(user.role_assignments) == 2 + assert user.is_admin is True + + def test_directory_second_super_admin_detected_via_role_assignments(self): + """Regression: a second super admin whose users.list().isAdmin still + reads False (e.g. API propagation lag, or only holding + _SEED_ADMIN_ROLE) must still be recognised as a super admin through + the Role Assignments API, AND any extra non-super-admin roles they + hold must be surfaced on their User object.""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + + stale_user_1 = { + "id": "user1-id", + "primaryEmail": "admin1@test-company.com", + "isAdmin": False, + } + stale_user_2 = { + "id": "user2-id", + "primaryEmail": "admin2@test-company.com", + "isAdmin": False, + } + mock_users_list = MagicMock() + mock_users_list.execute.return_value = {"users": [stale_user_1, stale_user_2]} + mock_service.users().list.return_value = mock_users_list + mock_service.users().list_next.return_value = None + + mock_roles_list = MagicMock() + mock_roles_list.execute.return_value = { + "items": [ROLE_SUPER_ADMIN, ROLE_SEED_ADMIN, ROLE_GROUPS_ADMIN] + } + mock_service.roles().list.return_value = mock_roles_list + mock_service.roles().list_next.return_value = None + + mock_ra = MagicMock() + mock_ra.execute.return_value = { + "items": [ + {"assignedTo": "user1-id", "roleId": SEED_ADMIN_ROLE_ID}, + {"assignedTo": "user2-id", "roleId": SUPER_ADMIN_ROLE_ID}, + {"assignedTo": "user2-id", "roleId": GROUPS_ADMIN_ROLE_ID}, + ] + } + mock_service.roleAssignments().list.return_value = mock_ra + mock_service.roleAssignments().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.directory.directory_service import ( + Directory, + ) + + directory = Directory(mock_provider) + + user1 = directory.users["user1-id"] + user2 = directory.users["user2-id"] + assert user1.is_admin is True + assert user2.is_admin is True + + assert [r.name for r in user1.role_assignments] == ["_SEED_ADMIN_ROLE"] + user2_role_names = {r.name for r in user2.role_assignments} + assert user2_role_names == {"Super Admin", "_GROUPS_ADMIN_ROLE"} diff --git a/tests/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles_test.py b/tests/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles_test.py new file mode 100644 index 0000000000..4025717bf7 --- /dev/null +++ b/tests/providers/googleworkspace/services/directory/directory_super_admin_only_admin_roles/directory_super_admin_only_admin_roles_test.py @@ -0,0 +1,446 @@ +from unittest.mock import patch + +from prowler.providers.googleworkspace.services.directory.directory_service import ( + Role, + User, +) +from tests.providers.googleworkspace.googleworkspace_fixtures import ( + CUSTOMER_ID, + DOMAIN, + set_mocked_googleworkspace_provider, +) + +SUPER_ADMIN_ROLE = Role( + id="13801188331880449", + name="Super Admin", + description="Super Admin", + is_super_admin_role=True, +) +SEED_ADMIN_ROLE = Role( + id="13801188331880451", + name="_SEED_ADMIN_ROLE", + description="Super Admin", + is_super_admin_role=True, +) +GROUPS_ADMIN_ROLE = Role( + id="13801188331880450", + name="_GROUPS_ADMIN_ROLE", + description="Groups Administrator", + is_super_admin_role=False, +) +USER_MANAGEMENT_ADMIN_ROLE = Role( + id="13801188331880452", + name="_USER_MANAGEMENT_ADMIN_ROLE", + description="User Management Administrator", + is_super_admin_role=False, +) +CUSTOM_ROLE_NO_DESCRIPTION = Role( + id="13801188331880453", + name="custom-helpdesk-role", + description="", + is_super_admin_role=False, +) + + +class TestDirectorySuperAdminOnlyAdminRoles: + def test_pass_super_admins_only_super_admin_role(self): + """Test PASS when super admins have only the Super Admin role""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE], + ), + "admin2-id": User( + id="admin2-id", + email="admin2@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE], + ), + "user1-id": User( + id="user1-id", + email="user@test-company.com", + is_admin=False, + role_assignments=[], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "used only for super admin activities" in findings[0].status_extended + assert findings[0].resource_name == DOMAIN + assert findings[0].customer_id == CUSTOMER_ID + + def test_pass_super_admin_with_seed_admin_role(self): + """Test PASS when a super admin only holds _SEED_ADMIN_ROLE. + + _SEED_ADMIN_ROLE is auto-assigned by Google to the original domain + creator and has isSuperAdminRole=True, so it must not count as an + "extra" role. + """ + users = { + "admin1-id": User( + id="admin1-id", + email="playground@prowler.cloud", + is_admin=True, + role_assignments=[SEED_ADMIN_ROLE], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "_SEED_ADMIN_ROLE" not in findings[0].status_extended + + def test_pass_super_admin_with_both_super_admin_and_seed_admin(self): + """Test PASS when admin holds both Super Admin and _SEED_ADMIN_ROLE""" + users = { + "admin1-id": User( + id="admin1-id", + email="playground@prowler.cloud", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE, SEED_ADMIN_ROLE], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + + def test_fail_super_admin_with_additional_roles(self): + """Test FAIL when a super admin also has additional admin roles""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE, GROUPS_ADMIN_ROLE], + ), + "user1-id": User( + id="user1-id", + email="user@test-company.com", + is_admin=False, + role_assignments=[], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "admin1@test-company.com" in findings[0].status_extended + assert "Groups Administrator" in findings[0].status_extended + assert "_GROUPS_ADMIN_ROLE" not in findings[0].status_extended + assert "used only for super admin activities" in findings[0].status_extended + assert findings[0].resource_name == DOMAIN + assert findings[0].customer_id == CUSTOMER_ID + + def test_fail_seed_admin_with_additional_roles(self): + """Test FAIL when a _SEED_ADMIN_ROLE holder also has extra roles""" + users = { + "admin1-id": User( + id="admin1-id", + email="playground@prowler.cloud", + is_admin=True, + role_assignments=[SEED_ADMIN_ROLE, GROUPS_ADMIN_ROLE], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "playground@prowler.cloud" in findings[0].status_extended + assert "Groups Administrator" in findings[0].status_extended + assert "_GROUPS_ADMIN_ROLE" not in findings[0].status_extended + assert "_SEED_ADMIN_ROLE" not in findings[0].status_extended + + def test_fail_multiple_super_admins_with_extra_roles(self): + """Test FAIL lists all super admins that have additional roles""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE, GROUPS_ADMIN_ROLE], + ), + "admin2-id": User( + id="admin2-id", + email="admin2@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE, USER_MANAGEMENT_ADMIN_ROLE], + ), + "admin3-id": User( + id="admin3-id", + email="admin3@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "admin1@test-company.com" in findings[0].status_extended + assert "admin2@test-company.com" in findings[0].status_extended + assert "admin3@test-company.com" not in findings[0].status_extended + + def test_no_findings_when_no_users(self): + """Test no findings when there are no users""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = {} + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 0 + + def test_non_super_admin_with_roles_not_flagged(self): + """Test that users who are not super admins are ignored even if they have roles""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE], + ), + "delegated1-id": User( + id="delegated1-id", + email="delegated@test-company.com", + is_admin=False, + role_assignments=[GROUPS_ADMIN_ROLE], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "delegated@test-company.com" not in findings[0].status_extended + + def test_pass_super_admin_with_empty_role_assignments(self): + """Test PASS when super admin has no role assignments (edge case)""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + + def test_fail_custom_role_without_description_falls_back_to_name(self): + """A custom role with an empty description should be displayed + using its name as a fall-back, so the FAIL message is never blank + for users that genuinely hold extra roles.""" + users = { + "admin1-id": User( + id="admin1-id", + email="admin1@test-company.com", + is_admin=True, + role_assignments=[SUPER_ADMIN_ROLE, CUSTOM_ROLE_NO_DESCRIPTION], + ), + } + + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles.directory_client" + ) as mock_directory_client, + ): + from prowler.providers.googleworkspace.services.directory.directory_super_admin_only_admin_roles.directory_super_admin_only_admin_roles import ( + directory_super_admin_only_admin_roles, + ) + + mock_directory_client.users = users + mock_directory_client.provider = mock_provider + + check = directory_super_admin_only_admin_roles() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "custom-helpdesk-role" in findings[0].status_extended From 9290d7e1052a7feb22692d5a8d8e26d201cecfd0 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:15:05 +0200 Subject: [PATCH 05/36] feat(sdk): warn when sensitive CLI flags receive explicit values (#10532) --- docs/developer-guide/provider.mdx | 29 +++++++++ docs/user-guide/cli/tutorials/pentesting.mdx | 32 +++++++--- prowler/CHANGELOG.md | 1 + prowler/lib/cli/parser.py | 9 ++- prowler/lib/cli/redact.py | 55 ++++++++++++++-- prowler/lib/cli/sensitive.py | 8 +++ .../providers/nhn/lib/arguments/arguments.py | 6 +- .../openstack/lib/arguments/arguments.py | 1 + skills/prowler-provider/SKILL.md | 28 ++++++++ tests/lib/cli/redact_test.py | 64 ++++++++++++++++++- 10 files changed, 215 insertions(+), 18 deletions(-) create mode 100644 prowler/lib/cli/sensitive.py diff --git a/docs/developer-guide/provider.mdx b/docs/developer-guide/provider.mdx index 0fb3bc549d..ec3e106150 100644 --- a/docs/developer-guide/provider.mdx +++ b/docs/developer-guide/provider.mdx @@ -750,6 +750,35 @@ def init_parser(self): # More arguments for the provider. ``` +##### Sensitive CLI Arguments + +CLI flags that accept secrets (tokens, passwords, API keys) require special handling to protect credentials from leaking in HTML output and process listings: + +1. **Use `nargs="?"` with `default=None`** so the flag works both with and without an inline value. This allows the provider to fall back to an environment variable when no value is passed. +2. **Add a `SENSITIVE_ARGUMENTS` frozenset** at the top of the `arguments.py` file listing every flag that accepts secret values: + + ```python + SENSITIVE_ARGUMENTS = frozenset({"--your-provider-password", "--your-provider-token"}) + ``` + + Prowler automatically discovers these frozensets and uses them to redact values in HTML output and warn users who pass secrets directly on the command line. + +3. **Document the environment variable** in the `help` text so users know the recommended alternative: + + ```python + _parser.add_argument( + "--your-provider-password", + nargs="?", + default=None, + metavar="PASSWORD", + help="Password for authentication. We recommend using the YOUR_PROVIDER_PASSWORD environment variable instead.", + ) + ``` + + +Do not add new arguments that require passing secrets as CLI values without an environment variable fallback. Prowler CLI warns users when sensitive flags receive explicit values on the command line. + + #### Step 5: Implement Mutelist **Explanation:** diff --git a/docs/user-guide/cli/tutorials/pentesting.mdx b/docs/user-guide/cli/tutorials/pentesting.mdx index f59c9ccc2e..0ad5313611 100644 --- a/docs/user-guide/cli/tutorials/pentesting.mdx +++ b/docs/user-guide/cli/tutorials/pentesting.mdx @@ -66,22 +66,38 @@ prowler --categories internet-exposed ### Shodan -Prowler allows you check if any public IPs in your Cloud environments are exposed in Shodan with the `-N`/`--shodan ` option: +Prowler can check whether any public IPs in cloud environments are exposed in Shodan using the `-N`/`--shodan` option. -For example, you can check if any of your AWS Elastic Compute Cloud (EC2) instances has an elastic IP exposed in Shodan: +#### Using the Environment Variable (Recommended) + +Set the `SHODAN_API_KEY` environment variable to avoid exposing the API key in process listings and shell history: ```console -prowler aws -N/--shodan -c ec2_elastic_ip_shodan +export SHODAN_API_KEY= ``` -Also, you can check if any of your Azure Subscription has an public IP exposed in Shodan: +Then run Prowler with the `--shodan` flag (no value needed): ```console -prowler azure -N/--shodan -c network_public_ip_shodan +prowler aws --shodan -c ec2_elastic_ip_shodan ``` -And finally, you can check if any of your GCP projects has an public IP address exposed in Shodan: - ```console -prowler gcp -N/--shodan -c compute_public_address_shodan +prowler azure --shodan -c network_public_ip_shodan ``` + +```console +prowler gcp --shodan -c compute_public_address_shodan +``` + +#### Using the CLI Flag + +Alternatively, pass the API key directly on the command line: + +```console +prowler aws --shodan -c ec2_elastic_ip_shodan +``` + + +Passing secret values directly on the command line exposes them in process listings and shell history. Prowler CLI displays a warning when this pattern is detected. Use the `SHODAN_API_KEY` environment variable instead. + diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index f483ce9d56..06d1aba5a8 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -25,6 +25,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Added `internet-exposed` category to 13 AWS checks (CloudFront, CodeArtifact, EC2, EFS, RDS, SageMaker, Shield, VPC) [(#10502)](https://github.com/prowler-cloud/prowler/pull/10502) - Minimum Python version from 3.9 to 3.10 and updated classifiers to reflect supported versions (3.10, 3.11, 3.12) [(#10464)](https://github.com/prowler-cloud/prowler/pull/10464) +- Sensitive CLI flags now warn when values are passed directly, recommending environment variables instead [(#10532)](https://github.com/prowler-cloud/prowler/pull/10532) ### ๐Ÿž Fixed diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index 47275b12cf..d2afa70e15 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -12,6 +12,7 @@ from prowler.config.config import ( default_output_directory, ) from prowler.lib.check.models import Severity +from prowler.lib.cli.redact import warn_sensitive_argument_values from prowler.lib.outputs.common import Status from prowler.providers.common.arguments import ( init_providers_parser, @@ -19,8 +20,6 @@ from prowler.providers.common.arguments import ( validate_provider_arguments, ) -SENSITIVE_ARGUMENTS = frozenset({"--shodan"}) - class ProwlerArgumentParser: # Set the default parser @@ -126,6 +125,10 @@ Detailed documentation at https://docs.prowler.com elif sys.argv[1] == "oci": sys.argv[1] = "oraclecloud" + # Warn about sensitive flags passed with explicit values + # Snapshot argv before parse_args() which may exit on errors + warn_sensitive_argument_values(list(sys.argv[1:])) + # Parse arguments args = self.parser.parse_args() @@ -434,7 +437,7 @@ Detailed documentation at https://docs.prowler.com nargs="?", default=None, metavar="SHODAN_API_KEY", - help="Check if any public IPs in your Cloud environments are exposed in Shodan.", + help="Check if any public IPs in your Cloud environments are exposed in Shodan. We recommend to use the SHODAN_API_KEY environment variable to provide the API key.", ) third_party_subparser.add_argument( "--slack", diff --git a/prowler/lib/cli/redact.py b/prowler/lib/cli/redact.py index 2dfd9e2bfa..3984139bae 100644 --- a/prowler/lib/cli/redact.py +++ b/prowler/lib/cli/redact.py @@ -1,6 +1,9 @@ from functools import lru_cache from importlib import import_module +from colorama import Fore, Style + +from prowler.lib.cli.sensitive import SENSITIVE_ARGUMENTS as COMMON_SENSITIVE_ARGUMENTS from prowler.lib.logger import logger from prowler.providers.common.provider import Provider, providers_path @@ -13,11 +16,7 @@ def get_sensitive_arguments() -> frozenset: sensitive: set[str] = set() # Common parser sensitive arguments (e.g., --shodan) - try: - parser_module = import_module("prowler.lib.cli.parser") - sensitive.update(getattr(parser_module, "SENSITIVE_ARGUMENTS", frozenset())) - except Exception as error: - logger.debug(f"Could not load SENSITIVE_ARGUMENTS from parser: {error}") + sensitive.update(COMMON_SENSITIVE_ARGUMENTS) # Provider-specific sensitive arguments for provider in Provider.get_available_providers(): @@ -66,3 +65,49 @@ def redact_argv(argv: list[str]) -> str: result.append(arg) return " ".join(result) + + +def warn_sensitive_argument_values(argv: list[str]) -> None: + """Log a warning for each sensitive CLI flag that was passed with an explicit value. + + Scans the raw argv list (not parsed args) to detect when users pass + secret values directly on the command line instead of using environment + variables. Handles both ``--flag value`` and ``--flag=value`` syntax. + + Args: + argv: The argument list to check (typically ``sys.argv[1:]``). + """ + sensitive = get_sensitive_arguments() + if not sensitive: + return + + use_color = "--no-color" not in argv + flags_with_values: list[str] = [] + + for i, arg in enumerate(argv): + # --flag=value syntax + if "=" in arg: + flag = arg.split("=", 1)[0] + if flag in sensitive: + flags_with_values.append(flag) + continue + + # --flag value syntax + if arg in sensitive: + if i + 1 < len(argv) and not argv[i + 1].startswith("-"): + flags_with_values.append(arg) + + for flag in flags_with_values: + if use_color: + logger.warning( + f"{Fore.YELLOW}{Style.BRIGHT}WARNING:{Style.RESET_ALL}{Fore.YELLOW} " + f"Passing a value directly to {flag} is not recommended. " + f"Use the corresponding environment variable instead to avoid " + f"exposing secrets in process listings and shell history.{Style.RESET_ALL}" + ) + else: + logger.warning( + f"Passing a value directly to {flag} is not recommended. " + f"Use the corresponding environment variable instead to avoid " + f"exposing secrets in process listings and shell history." + ) diff --git a/prowler/lib/cli/sensitive.py b/prowler/lib/cli/sensitive.py new file mode 100644 index 0000000000..4f5ad004d7 --- /dev/null +++ b/prowler/lib/cli/sensitive.py @@ -0,0 +1,8 @@ +"""Common parser sensitive arguments. + +This module is kept dependency-free (no prowler-internal imports) so that +``prowler.lib.cli.redact`` and any provider argument module can import it +without circular-import risk. +""" + +SENSITIVE_ARGUMENTS = frozenset({"--shodan"}) diff --git a/prowler/providers/nhn/lib/arguments/arguments.py b/prowler/providers/nhn/lib/arguments/arguments.py index 8f7c71fd7c..a102665a26 100644 --- a/prowler/providers/nhn/lib/arguments/arguments.py +++ b/prowler/providers/nhn/lib/arguments/arguments.py @@ -13,7 +13,11 @@ def init_parser(self): "--nhn-username", nargs="?", default=None, help="NHN API Username" ) nhn_auth_subparser.add_argument( - "--nhn-password", nargs="?", default=None, help="NHN API Password" + "--nhn-password", + nargs="?", + default=None, + metavar="NHN_PASSWORD", + help="NHN API Password", ) nhn_auth_subparser.add_argument( "--nhn-tenant-id", nargs="?", default=None, help="NHN Tenant ID" diff --git a/prowler/providers/openstack/lib/arguments/arguments.py b/prowler/providers/openstack/lib/arguments/arguments.py index 459012c4ec..68674528b6 100644 --- a/prowler/providers/openstack/lib/arguments/arguments.py +++ b/prowler/providers/openstack/lib/arguments/arguments.py @@ -46,6 +46,7 @@ def init_parser(self): "--os-password", nargs="?", default=None, + metavar="OS_PASSWORD", help="OpenStack password for authentication. Can also be set via OS_PASSWORD environment variable", ) openstack_explicit_subparser.add_argument( diff --git a/skills/prowler-provider/SKILL.md b/skills/prowler-provider/SKILL.md index 994d134776..c9f2811e97 100644 --- a/skills/prowler-provider/SKILL.md +++ b/skills/prowler-provider/SKILL.md @@ -45,6 +45,34 @@ prowler/providers/{provider}/ โ””โ”€โ”€ {check_name}.metadata.json ``` +## Sensitive CLI Arguments + +Flags that accept secrets (tokens, passwords, API keys) MUST follow these rules: + +1. **Use `nargs="?"` with `default=None`** โ€” the flag accepts an optional value for backward compatibility; the recommended path is environment variables. +2. **Set `metavar` to the environment variable name** users should use (e.g., `metavar="GITHUB_PERSONAL_ACCESS_TOKEN"`). +3. **Add the flag to the `SENSITIVE_ARGUMENTS` frozenset** at the top of the provider's `arguments.py`. This set is used to redact values in HTML output and warn users who pass secrets directly. +4. **Do not add new arguments that require passing secrets as CLI values** โ€” secrets should come from environment variables. The flag accepts a value for backward compatibility, but CLI warns users to prefer env vars. + +### Pattern + +```python +# prowler/providers/{provider}/lib/arguments/arguments.py + +SENSITIVE_ARGUMENTS = frozenset({"--my-api-key", "--my-password"}) + + +def init_parser(self): + auth_subparser = parser.add_argument_group("Authentication Modes") + auth_subparser.add_argument( + "--my-api-key", + nargs="?", + default=None, + metavar="MY_API_KEY", + help="API key for authentication. Use MY_API_KEY env var instead of passing directly.", + ) +``` + ## Provider Class Template ```python diff --git a/tests/lib/cli/redact_test.py b/tests/lib/cli/redact_test.py index 1f33998356..5de4cc8fd7 100644 --- a/tests/lib/cli/redact_test.py +++ b/tests/lib/cli/redact_test.py @@ -1,8 +1,14 @@ +import logging from unittest.mock import patch import pytest -from prowler.lib.cli.redact import REDACTED_VALUE, get_sensitive_arguments, redact_argv +from prowler.lib.cli.redact import ( + REDACTED_VALUE, + get_sensitive_arguments, + redact_argv, + warn_sensitive_argument_values, +) @pytest.fixture @@ -87,6 +93,62 @@ class TestRedactArgv: assert redact_argv(argv) == "aws --region=us-east-1" +class TestWarnSensitiveArgumentValues: + def test_no_warning_without_sensitive_flags(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values(["aws", "--region", "eu-west-1"]) + assert caplog.text == "" + + def test_no_warning_flag_without_value(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values(["github", "--personal-access-token"]) + assert caplog.text == "" + + def test_no_warning_flag_followed_by_another_flag( + self, caplog, mock_sensitive_args + ): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values( + ["github", "--personal-access-token", "--region", "eu-west-1"] + ) + assert caplog.text == "" + + def test_warning_flag_with_value(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values( + ["github", "--personal-access-token", "ghp_secret"] + ) + assert "--personal-access-token" in caplog.text + assert "not recommended" in caplog.text + + def test_warning_flag_with_equals_syntax(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values(["aws", "--shodan=key123"]) + assert "--shodan" in caplog.text + assert "not recommended" in caplog.text + + def test_warning_multiple_flags(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values( + [ + "github", + "--personal-access-token", + "ghp_secret", + "--shodan", + "key", + ] + ) + assert "--personal-access-token" in caplog.text + assert "--shodan" in caplog.text + + def test_no_color_output(self, caplog, mock_sensitive_args): + with caplog.at_level(logging.WARNING): + warn_sensitive_argument_values(["--no-color", "aws", "--shodan", "key123"]) + assert "not recommended" in caplog.text + # Should not contain ANSI escape codes + assert "\033[" not in caplog.text + + class TestGetSensitiveArguments: def test_discovers_known_sensitive_arguments(self): """Integration test: verify the discovery mechanism finds flags from provider modules.""" From bc38104903f6944d15216b65e4813de40951441e Mon Sep 17 00:00:00 2001 From: lydiavilchez <114735608+lydiavilchez@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:26:56 +0200 Subject: [PATCH 06/36] feat(googleworkspace): add calendar service checks using Cloud Identity Policy API (#10597) --- .../googleworkspace/authentication.mdx | 39 ++- prowler/CHANGELOG.md | 1 + .../cis_1.3_googleworkspace.json | 12 +- .../cisa_scuba_0.6_googleworkspace.json | 12 +- .../googleworkspace_provider.py | 16 +- .../services/calendar/__init__.py | 0 .../services/calendar/calendar_client.py | 6 + .../__init__.py | 0 ...external_invitations_warning.metadata.json | 41 ++++ .../calendar_external_invitations_warning.py | 56 +++++ .../__init__.py | 0 ...nal_sharing_primary_calendar.metadata.json | 41 ++++ ...endar_external_sharing_primary_calendar.py | 56 +++++ .../__init__.py | 0 ...l_sharing_secondary_calendar.metadata.json | 41 ++++ ...dar_external_sharing_secondary_calendar.py | 56 +++++ .../services/calendar/calendar_service.py | 112 +++++++++ ...endar_external_invitations_warning_test.py | 130 ++++++++++ ..._external_sharing_primary_calendar_test.py | 161 ++++++++++++ ...xternal_sharing_secondary_calendar_test.py | 161 ++++++++++++ .../calendar/calendar_service_test.py | 231 ++++++++++++++++++ 21 files changed, 1150 insertions(+), 22 deletions(-) create mode 100644 prowler/providers/googleworkspace/services/calendar/__init__.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_client.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/__init__.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.metadata.json create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/__init__.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.metadata.json create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/__init__.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.metadata.json create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.py create mode 100644 prowler/providers/googleworkspace/services/calendar/calendar_service.py create mode 100644 tests/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning_test.py create mode 100644 tests/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar_test.py create mode 100644 tests/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar_test.py create mode 100644 tests/providers/googleworkspace/services/calendar/calendar_service_test.py diff --git a/docs/user-guide/providers/googleworkspace/authentication.mdx b/docs/user-guide/providers/googleworkspace/authentication.mdx index e5c3527f89..b070c443b3 100644 --- a/docs/user-guide/providers/googleworkspace/authentication.mdx +++ b/docs/user-guide/providers/googleworkspace/authentication.mdx @@ -6,17 +6,18 @@ import { VersionBadge } from "/snippets/version-badge.mdx" -Prowler for Google Workspace uses a **Service Account with Domain-Wide Delegation** to authenticate to the Google Workspace Admin SDK. This allows Prowler to read directory data on behalf of a super administrator without requiring an interactive login. +Prowler for Google Workspace uses a **Service Account with Domain-Wide Delegation** to authenticate to the Google Workspace Admin SDK and the Cloud Identity Policy API. This allows Prowler to read directory data and domain-level application policies on behalf of a super administrator without requiring an interactive login. ## Required Open Authorization (OAuth) Scopes -Prowler requests the following read-only OAuth 2.0 scopes from the Google Workspace Admin SDK: +Prowler requests the following read-only OAuth 2.0 scopes: | Scope | Description | |-------|-------------| | `https://www.googleapis.com/auth/admin.directory.user.readonly` | Read access to user accounts and their admin status | | `https://www.googleapis.com/auth/admin.directory.domain.readonly` | Read access to domain information | | `https://www.googleapis.com/auth/admin.directory.customer.readonly` | Read access to customer information (Customer ID) | +| `https://www.googleapis.com/auth/cloud-identity.policies.readonly` | Read access to domain-level application policies (required for Calendar service checks) | | `https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly` | Read access to admin roles and role assignments | @@ -31,13 +32,24 @@ If no GCP project exists, create one at [https://console.cloud.google.com](https The project is only used to host the Service Account โ€” it does not need to have any Google Workspace data in it. -### Step 2: Enable the Admin SDK API +### Step 2: Enable Required APIs -1. Navigate to the [Google Cloud Console](https://console.cloud.google.com) -2. Select the target project -3. Navigate to **APIs & Services โ†’ Library** -4. Search for **Admin SDK API** -5. Click **Enable** +In the [Google Cloud Console](https://console.cloud.google.com), select the target project and navigate to **APIs & Services โ†’ Library**. Search for and enable each of the following APIs: + +| API | Required For | +|-----|--------------| +| **Admin SDK API** | Directory service checks (users, roles, domains) | +| **Cloud Identity API** | Calendar service checks (domain-level sharing and invitation policies) | + +For each API: + +1. Search for the API name in the library +2. Click the API result +3. Click **Enable** + + +Both APIs must be enabled in the same GCP project that hosts the Service Account. Calendar checks will return no findings if the Cloud Identity API is not enabled. + ### Step 3: Create a Service Account @@ -74,7 +86,7 @@ This JSON key grants access to your Google Workspace organization. Never commit 6. In the **OAuth scopes** field, enter the following scopes as a comma-separated list: ``` -https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly,https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly +https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly,https://www.googleapis.com/auth/cloud-identity.policies.readonly,https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly ``` 7. Click **Authorize** @@ -162,3 +174,12 @@ If Prowler connects but returns empty results or permission errors for specific - Confirm Domain-Wide Delegation is fully propagated (wait a few minutes after setup) - Verify all scopes are authorized in the Admin Console - Ensure the delegated user is an active super administrator + +### Calendar Checks Return No Findings + +If the Directory checks run successfully but the Calendar checks (e.g., `calendar_external_sharing_primary_calendar`) return no findings, the Cloud Identity Policy API is not reachable for this Service Account. Verify: + +- The **Cloud Identity API** is enabled in the GCP project hosting the Service Account (Step 2) +- The scope `https://www.googleapis.com/auth/cloud-identity.policies.readonly` is included in the Domain-Wide Delegation OAuth scopes list in the Admin Console (Step 5) +- The delegated user is a super administrator (the Policy API only returns data to super admins) +- Domain-Wide Delegation has had time to propagate after adding the new scope (a few minutes) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 06d1aba5a8..56c363b9cf 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `--resource-group` and `--list-resource-groups` CLI flags to filter checks by resource group across all providers [(#10479)](https://github.com/prowler-cloud/prowler/pull/10479) - CISA SCuBA Google Workspace Baselines compliance [(#10466)](https://github.com/prowler-cloud/prowler/pull/10466) - CIS Google Workspace Foundations Benchmark v1.3.0 compliance [(#10462)](https://github.com/prowler-cloud/prowler/pull/10462) +- `calendar_external_sharing_primary_calendar`, `calendar_external_sharing_secondary_calendar`, and `calendar_external_invitations_warning` checks for Google Workspace provider using the Cloud Identity Policy API [(#10597)](https://github.com/prowler-cloud/prowler/pull/10597) - `entra_conditional_access_policy_device_registration_mfa_required` check and `entra_intune_enrollment_sign_in_frequency_every_time` enhancement for M365 provider [(#10222)](https://github.com/prowler-cloud/prowler/pull/10222) - `entra_conditional_access_policy_block_elevated_insider_risk` check for M365 provider [(#10234)](https://github.com/prowler-cloud/prowler/pull/10234) - `Vercel` provider support with 30 checks [(#10189)](https://github.com/prowler-cloud/prowler/pull/10189) diff --git a/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json b/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json index 7792bba0da..5d99d82c73 100644 --- a/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json +++ b/prowler/compliance/googleworkspace/cis_1.3_googleworkspace.json @@ -98,7 +98,9 @@ { "Id": "3.1.1.1.1", "Description": "Ensure external sharing options for primary calendars are configured", - "Checks": [], + "Checks": [ + "calendar_external_sharing_primary_calendar" + ], "Attributes": [ { "Section": "3 Apps", @@ -140,7 +142,9 @@ { "Id": "3.1.1.1.3", "Description": "Ensure external invitation warnings for Google Calendar are configured", - "Checks": [], + "Checks": [ + "calendar_external_invitations_warning" + ], "Attributes": [ { "Section": "3 Apps", @@ -161,7 +165,9 @@ { "Id": "3.1.1.2.1", "Description": "Ensure external sharing options for secondary calendars are configured", - "Checks": [], + "Checks": [ + "calendar_external_sharing_secondary_calendar" + ], "Attributes": [ { "Section": "3 Apps", diff --git a/prowler/compliance/googleworkspace/cisa_scuba_0.6_googleworkspace.json b/prowler/compliance/googleworkspace/cisa_scuba_0.6_googleworkspace.json index 17c2b88b2c..e81f4c70a3 100644 --- a/prowler/compliance/googleworkspace/cisa_scuba_0.6_googleworkspace.json +++ b/prowler/compliance/googleworkspace/cisa_scuba_0.6_googleworkspace.json @@ -1310,7 +1310,9 @@ { "Id": "GWS.CALENDAR.1.1", "Description": "External Sharing Options for Primary Calendars SHALL be configured to Only free/busy information (hide event details)", - "Checks": [], + "Checks": [ + "calendar_external_sharing_primary_calendar" + ], "Attributes": [ { "Section": "Calendar", @@ -1323,7 +1325,9 @@ { "Id": "GWS.CALENDAR.1.2", "Description": "External sharing options for secondary calendars SHALL be configured to Only free/busy information (hide event details)", - "Checks": [], + "Checks": [ + "calendar_external_sharing_secondary_calendar" + ], "Attributes": [ { "Section": "Calendar", @@ -1336,7 +1340,9 @@ { "Id": "GWS.CALENDAR.2.1", "Description": "External invitations warnings SHALL be enabled to prompt users before sending invitations", - "Checks": [], + "Checks": [ + "calendar_external_invitations_warning" + ], "Attributes": [ { "Section": "Calendar", diff --git a/prowler/providers/googleworkspace/googleworkspace_provider.py b/prowler/providers/googleworkspace/googleworkspace_provider.py index 549831a2fb..563078f1e3 100644 --- a/prowler/providers/googleworkspace/googleworkspace_provider.py +++ b/prowler/providers/googleworkspace/googleworkspace_provider.py @@ -59,11 +59,13 @@ class GoogleworkspaceProvider(Provider): _mutelist: GoogleWorkspaceMutelist audit_metadata: Audit_Metadata - # Google Workspace Admin SDK OAuth2 scopes - DIRECTORY_SCOPES = [ + # Google Workspace OAuth2 scopes + SCOPES = [ "https://www.googleapis.com/auth/admin.directory.user.readonly", "https://www.googleapis.com/auth/admin.directory.domain.readonly", "https://www.googleapis.com/auth/admin.directory.customer.readonly", + # Cloud Identity Policy API (calendar and other app policies) + "https://www.googleapis.com/auth/cloud-identity.policies.readonly", "https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly", ] @@ -215,7 +217,7 @@ class GoogleworkspaceProvider(Provider): try: credentials = service_account.Credentials.from_service_account_file( credentials_file, - scopes=GoogleworkspaceProvider.DIRECTORY_SCOPES, + scopes=GoogleworkspaceProvider.SCOPES, ) except FileNotFoundError as error: raise GoogleWorkspaceInvalidCredentialsError( @@ -242,7 +244,7 @@ class GoogleworkspaceProvider(Provider): try: credentials = service_account.Credentials.from_service_account_info( credentials_data, - scopes=GoogleworkspaceProvider.DIRECTORY_SCOPES, + scopes=GoogleworkspaceProvider.SCOPES, ) except ValueError as error: raise GoogleWorkspaceInvalidCredentialsError( @@ -265,7 +267,7 @@ class GoogleworkspaceProvider(Provider): try: credentials = service_account.Credentials.from_service_account_file( env_file, - scopes=GoogleworkspaceProvider.DIRECTORY_SCOPES, + scopes=GoogleworkspaceProvider.SCOPES, ) except FileNotFoundError as error: raise GoogleWorkspaceInvalidCredentialsError( @@ -294,7 +296,7 @@ class GoogleworkspaceProvider(Provider): try: credentials = service_account.Credentials.from_service_account_info( credentials_data, - scopes=GoogleworkspaceProvider.DIRECTORY_SCOPES, + scopes=GoogleworkspaceProvider.SCOPES, ) except ValueError as error: raise GoogleWorkspaceInvalidCredentialsError( @@ -415,7 +417,7 @@ class GoogleworkspaceProvider(Provider): ) # Fetch all domains (primary + aliases) to support domain aliases - # The scope admin.directory.domain.readonly is already in DIRECTORY_SCOPES + # The scope admin.directory.domain.readonly is already in SCOPES above try: domains_response = service.domains().list(customer="my_customer").execute() valid_domains = [ diff --git a/prowler/providers/googleworkspace/services/calendar/__init__.py b/prowler/providers/googleworkspace/services/calendar/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_client.py b/prowler/providers/googleworkspace/services/calendar/calendar_client.py new file mode 100644 index 0000000000..9162bb3207 --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_client.py @@ -0,0 +1,6 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, +) + +calendar_client = Calendar(Provider.get_global_provider()) diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/__init__.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.metadata.json b/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.metadata.json new file mode 100644 index 0000000000..3a47f981d0 --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.metadata.json @@ -0,0 +1,41 @@ +{ + "Provider": "googleworkspace", + "CheckID": "calendar_external_invitations_warning", + "CheckTitle": "External invitation warnings are enabled for Google Calendar", + "CheckType": [], + "ServiceName": "calendar", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "NotDefined", + "ResourceGroup": "collaboration", + "Description": "Google Calendar **warns users** when they invite guests from outside the organization to an event. This prompt gives users a chance to reconsider before sharing meeting details with external parties, reducing the likelihood of **accidental information disclosure** through calendar invitations.", + "Risk": "Without external invitation warnings, users may unintentionally include **external guests** in internal meetings, exposing **confidential meeting details**, agendas, and internal attendee lists to unauthorized parties. This is a common vector for inadvertent data leakage through everyday calendar actions.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://support.google.com/a/answer/6329284", + "https://knowledge.workspace.google.com/admin/calendar/set-google-calendar-sharing-options", + "https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings" + ], + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Calendar**\n3. Click **Sharing settings**\n4. Under **External invitations**, check **Warn users when inviting guests outside of the domain**\n5. Click **Save**", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable external invitation warnings so users are notified whenever a meeting invitation includes guests outside the organization. This simple prompt helps prevent accidental disclosure of meeting details to unintended recipients.", + "Url": "https://hub.prowler.com/check/calendar_external_invitations_warning" + } + }, + "Categories": [ + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [ + "calendar_external_sharing_primary_calendar", + "calendar_external_sharing_secondary_calendar" + ], + "Notes": "" +} diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.py new file mode 100644 index 0000000000..7af51cbfba --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning.py @@ -0,0 +1,56 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGoogleWorkspace +from prowler.providers.googleworkspace.services.calendar.calendar_client import ( + calendar_client, +) + + +class calendar_external_invitations_warning(Check): + """Check that external invitation warnings are enabled for Google Calendar + + This check verifies that the domain-level policy warns users when they + invite guests from outside the organization, reducing the risk of accidental + information disclosure through calendar events. + """ + + def execute(self) -> List[CheckReportGoogleWorkspace]: + findings = [] + + if calendar_client.policies_fetched: + report = CheckReportGoogleWorkspace( + metadata=self.metadata(), + resource=calendar_client.provider.identity, + resource_name=calendar_client.provider.identity.domain, + resource_id=calendar_client.provider.identity.customer_id, + customer_id=calendar_client.provider.identity.customer_id, + location="global", + ) + + warning_enabled = calendar_client.policies.external_invitations_warning + + if warning_enabled is True: + report.status = "PASS" + report.status_extended = ( + f"External invitation warnings for Google Calendar are enabled " + f"in domain {calendar_client.provider.identity.domain}." + ) + else: + report.status = "FAIL" + if warning_enabled is None: + report.status_extended = ( + f"External invitation warnings for Google Calendar are not " + f"explicitly configured in domain " + f"{calendar_client.provider.identity.domain}. " + f"Users should be warned when inviting guests outside the organization." + ) + else: + report.status_extended = ( + f"External invitation warnings for Google Calendar are disabled " + f"in domain {calendar_client.provider.identity.domain}. " + f"Users should be warned when inviting guests outside the organization." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/__init__.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.metadata.json b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.metadata.json new file mode 100644 index 0000000000..536e8413f2 --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.metadata.json @@ -0,0 +1,41 @@ +{ + "Provider": "googleworkspace", + "CheckID": "calendar_external_sharing_primary_calendar", + "CheckTitle": "External sharing for primary calendars is restricted to free/busy only", + "CheckType": [], + "ServiceName": "calendar", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "NotDefined", + "ResourceGroup": "collaboration", + "Description": "Primary calendars in the Google Workspace domain share **only free/busy information** with external users. When external sharing is set to share full event details, sensitive information such as meeting titles, attendees, locations, and descriptions is exposed to users outside the organization.", + "Risk": "Overly permissive external sharing of primary calendars exposes **sensitive meeting metadata** โ€” titles, attendees, locations, and descriptions โ€” to users outside the organization. This increases the risk of **information disclosure**, **social engineering**, and **targeted phishing** based on insights into organizational activities.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://support.google.com/a/answer/60765", + "https://knowledge.workspace.google.com/admin/calendar/set-google-calendar-sharing-options", + "https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings" + ], + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Calendar**\n3. Click **Sharing settings**\n4. Under **External sharing options for primary calendars**, select **Only free/busy information (hide event details)**\n5. Click **Save**", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict external sharing of primary calendars to free/busy information only. This preserves scheduling functionality with external users while preventing exposure of sensitive meeting details.", + "Url": "https://hub.prowler.com/check/calendar_external_sharing_primary_calendar" + } + }, + "Categories": [ + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [ + "calendar_external_sharing_secondary_calendar", + "calendar_external_invitations_warning" + ], + "Notes": "" +} diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.py new file mode 100644 index 0000000000..b019acf4de --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar.py @@ -0,0 +1,56 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGoogleWorkspace +from prowler.providers.googleworkspace.services.calendar.calendar_client import ( + calendar_client, +) + + +class calendar_external_sharing_primary_calendar(Check): + """Check that external sharing for primary calendars is restricted to free/busy only + + This check verifies that the domain-level policy for primary calendar external + sharing is set to share only free/busy information, preventing exposure of + event details to external users. + """ + + def execute(self) -> List[CheckReportGoogleWorkspace]: + findings = [] + + if calendar_client.policies_fetched: + report = CheckReportGoogleWorkspace( + metadata=self.metadata(), + resource=calendar_client.provider.identity, + resource_name=calendar_client.provider.identity.domain, + resource_id=calendar_client.provider.identity.customer_id, + customer_id=calendar_client.provider.identity.customer_id, + location="global", + ) + + sharing = calendar_client.policies.primary_calendar_external_sharing + + if sharing == "EXTERNAL_FREE_BUSY_ONLY": + report.status = "PASS" + report.status_extended = ( + f"Primary calendar external sharing in domain " + f"{calendar_client.provider.identity.domain} is restricted to " + f"free/busy information only." + ) + else: + report.status = "FAIL" + if sharing is None: + report.status_extended = ( + f"Primary calendar external sharing is not explicitly configured " + f"in domain {calendar_client.provider.identity.domain}. " + f"External sharing should be restricted to free/busy information only." + ) + else: + report.status_extended = ( + f"Primary calendar external sharing in domain " + f"{calendar_client.provider.identity.domain} is set to {sharing}. " + f"External sharing should be restricted to free/busy information only." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/__init__.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.metadata.json b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.metadata.json new file mode 100644 index 0000000000..1dadf4965c --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.metadata.json @@ -0,0 +1,41 @@ +{ + "Provider": "googleworkspace", + "CheckID": "calendar_external_sharing_secondary_calendar", + "CheckTitle": "External sharing for secondary calendars is restricted to free/busy only", + "CheckType": [], + "ServiceName": "calendar", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "medium", + "ResourceType": "NotDefined", + "ResourceGroup": "collaboration", + "Description": "Secondary calendars in the Google Workspace domain share **only free/busy information** with external users. Secondary calendars are additional calendars users create beyond their primary calendar (e.g., for projects, teams, or personal events), and are commonly used to organize sensitive or focused activities that should not be visible to external parties.", + "Risk": "Overly permissive external sharing of secondary calendars exposes **project-specific or team-specific event details** to users outside the organization. Because secondary calendars often hold more targeted activities (e.g., product launches, internal reviews), unrestricted external sharing increases the risk of **information disclosure** and **competitive intelligence leakage**.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://support.google.com/a/answer/60765", + "https://knowledge.workspace.google.com/admin/calendar/set-google-calendar-sharing-options", + "https://cloud.google.com/identity/docs/concepts/supported-policy-api-settings" + ], + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "1. Sign in to the Google **Admin console** at https://admin.google.com\n2. Navigate to **Apps** > **Google Workspace** > **Calendar**\n3. Click **Sharing settings**\n4. Under **External sharing options for secondary calendars**, select **Only free/busy information (hide event details)**\n5. Click **Save**", + "Terraform": "" + }, + "Recommendation": { + "Text": "Restrict external sharing of secondary calendars to free/busy information only. This preserves scheduling interoperability with external collaborators while preventing exposure of sensitive event details in user-created calendars.", + "Url": "https://hub.prowler.com/check/calendar_external_sharing_secondary_calendar" + } + }, + "Categories": [ + "internet-exposed" + ], + "DependsOn": [], + "RelatedTo": [ + "calendar_external_sharing_primary_calendar", + "calendar_external_invitations_warning" + ], + "Notes": "" +} diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.py b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.py new file mode 100644 index 0000000000..f7a418b48e --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar.py @@ -0,0 +1,56 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportGoogleWorkspace +from prowler.providers.googleworkspace.services.calendar.calendar_client import ( + calendar_client, +) + + +class calendar_external_sharing_secondary_calendar(Check): + """Check that external sharing for secondary calendars is restricted to free/busy only + + This check verifies that the domain-level policy for secondary calendar external + sharing is set to share only free/busy information, preventing exposure of + event details in user-created calendars to external users. + """ + + def execute(self) -> List[CheckReportGoogleWorkspace]: + findings = [] + + if calendar_client.policies_fetched: + report = CheckReportGoogleWorkspace( + metadata=self.metadata(), + resource=calendar_client.provider.identity, + resource_name=calendar_client.provider.identity.domain, + resource_id=calendar_client.provider.identity.customer_id, + customer_id=calendar_client.provider.identity.customer_id, + location="global", + ) + + sharing = calendar_client.policies.secondary_calendar_external_sharing + + if sharing == "EXTERNAL_FREE_BUSY_ONLY": + report.status = "PASS" + report.status_extended = ( + f"Secondary calendar external sharing in domain " + f"{calendar_client.provider.identity.domain} is restricted to " + f"free/busy information only." + ) + else: + report.status = "FAIL" + if sharing is None: + report.status_extended = ( + f"Secondary calendar external sharing is not explicitly configured " + f"in domain {calendar_client.provider.identity.domain}. " + f"External sharing should be restricted to free/busy information only." + ) + else: + report.status_extended = ( + f"Secondary calendar external sharing in domain " + f"{calendar_client.provider.identity.domain} is set to {sharing}. " + f"External sharing should be restricted to free/busy information only." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/googleworkspace/services/calendar/calendar_service.py b/prowler/providers/googleworkspace/services/calendar/calendar_service.py new file mode 100644 index 0000000000..ae71c0fdf1 --- /dev/null +++ b/prowler/providers/googleworkspace/services/calendar/calendar_service.py @@ -0,0 +1,112 @@ +from typing import Optional + +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.googleworkspace.lib.service.service import GoogleWorkspaceService + + +class Calendar(GoogleWorkspaceService): + """Google Workspace Calendar service for auditing domain-level calendar policies. + + Uses the Cloud Identity Policy API v1 to read calendar sharing + and invitation settings configured in the Admin Console. + """ + + def __init__(self, provider): + super().__init__(provider) + self.policies = CalendarPolicies() + self.policies_fetched = False + self._fetch_calendar_policies() + + def _fetch_calendar_policies(self): + """Fetch calendar policies from the Cloud Identity Policy API v1.""" + logger.info("Calendar - Fetching calendar policies...") + + try: + service = self._build_service("cloudidentity", "v1") + + if not service: + logger.error("Failed to build Cloud Identity service") + return + + request = service.policies().list(pageSize=100) + fetch_succeeded = True + + while request is not None: + try: + response = request.execute() + + for policy in response.get("policies", []): + setting = policy.get("setting", {}) + setting_type = setting.get("type", "").removeprefix("settings/") + value = setting.get("value", {}) + + if ( + setting_type + == "calendar.primary_calendar_max_allowed_external_sharing" + ): + self.policies.primary_calendar_external_sharing = value.get( + "maxAllowedExternalSharing" + ) + logger.debug( + "Primary calendar external sharing: " + f"{self.policies.primary_calendar_external_sharing}" + ) + + elif ( + setting_type + == "calendar.secondary_calendar_max_allowed_external_sharing" + ): + self.policies.secondary_calendar_external_sharing = ( + value.get("maxAllowedExternalSharing") + ) + logger.debug( + "Secondary calendar external sharing: " + f"{self.policies.secondary_calendar_external_sharing}" + ) + + elif setting_type == "calendar.external_invitations": + self.policies.external_invitations_warning = value.get( + "warnOnInvite" + ) + logger.debug( + "External invitations warning: " + f"{self.policies.external_invitations_warning}" + ) + + request = service.policies().list_next(request, response) + + except Exception as error: + self._handle_api_error( + error, + "fetching calendar policies", + self.provider.identity.customer_id, + ) + fetch_succeeded = False + break + + self.policies_fetched = fetch_succeeded + + logger.info( + f"Calendar policies fetched - " + f"Primary sharing: {self.policies.primary_calendar_external_sharing}, " + f"Secondary sharing: {self.policies.secondary_calendar_external_sharing}, " + f"Invitation warnings: {self.policies.external_invitations_warning}" + ) + + except Exception as error: + self._handle_api_error( + error, + "fetching calendar policies", + self.provider.identity.customer_id, + ) + self.policies_fetched = False + + +class CalendarPolicies(BaseModel): + """Model for domain-level Calendar policy settings.""" + + primary_calendar_external_sharing: Optional[str] = None + secondary_calendar_external_sharing: Optional[str] = None + external_invitations_warning: Optional[bool] = None diff --git a/tests/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning_test.py b/tests/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning_test.py new file mode 100644 index 0000000000..f367d5938d --- /dev/null +++ b/tests/providers/googleworkspace/services/calendar/calendar_external_invitations_warning/calendar_external_invitations_warning_test.py @@ -0,0 +1,130 @@ +from unittest.mock import patch + +from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + CalendarPolicies, +) +from tests.providers.googleworkspace.googleworkspace_fixtures import ( + CUSTOMER_ID, + DOMAIN, + set_mocked_googleworkspace_provider, +) + + +class TestCalendarExternalInvitationsWarning: + def test_pass_warnings_enabled(self): + """Test PASS when external invitation warnings are enabled""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning import ( + calendar_external_invitations_warning, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + external_invitations_warning=True + ) + + check = calendar_external_invitations_warning() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "enabled" in findings[0].status_extended + assert findings[0].resource_name == DOMAIN + assert findings[0].customer_id == CUSTOMER_ID + + def test_fail_warnings_disabled(self): + """Test FAIL when external invitation warnings are disabled""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning import ( + calendar_external_invitations_warning, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + external_invitations_warning=False + ) + + check = calendar_external_invitations_warning() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "disabled" in findings[0].status_extended + + def test_fail_no_policy_set(self): + """Test FAIL when no explicit policy is set (None) but fetch succeeded""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning import ( + calendar_external_invitations_warning, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + external_invitations_warning=None + ) + + check = calendar_external_invitations_warning() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "not explicitly configured" in findings[0].status_extended + + def test_no_findings_when_fetch_failed(self): + """Test no findings returned when the API fetch failed""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_invitations_warning.calendar_external_invitations_warning import ( + calendar_external_invitations_warning, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = False + mock_calendar_client.policies = CalendarPolicies() + + check = calendar_external_invitations_warning() + findings = check.execute() + + assert len(findings) == 0 diff --git a/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar_test.py b/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar_test.py new file mode 100644 index 0000000000..32056e9fcb --- /dev/null +++ b/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_primary_calendar/calendar_external_sharing_primary_calendar_test.py @@ -0,0 +1,161 @@ +from unittest.mock import patch + +from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + CalendarPolicies, +) +from tests.providers.googleworkspace.googleworkspace_fixtures import ( + CUSTOMER_ID, + DOMAIN, + set_mocked_googleworkspace_provider, +) + + +class TestCalendarExternalSharingPrimaryCalendar: + def test_pass_free_busy_only(self): + """Test PASS when external sharing is restricted to free/busy only""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar import ( + calendar_external_sharing_primary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + primary_calendar_external_sharing="EXTERNAL_FREE_BUSY_ONLY" + ) + + check = calendar_external_sharing_primary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "free/busy information only" in findings[0].status_extended + assert findings[0].resource_name == DOMAIN + assert findings[0].customer_id == CUSTOMER_ID + + def test_fail_read_only(self): + """Test FAIL when external sharing allows read-only access""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar import ( + calendar_external_sharing_primary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + primary_calendar_external_sharing="EXTERNAL_ALL_INFO_READ_ONLY" + ) + + check = calendar_external_sharing_primary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "EXTERNAL_ALL_INFO_READ_ONLY" in findings[0].status_extended + assert "free/busy information only" in findings[0].status_extended + + def test_fail_read_write(self): + """Test FAIL when external sharing allows read-write access""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar import ( + calendar_external_sharing_primary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + primary_calendar_external_sharing="EXTERNAL_ALL_INFO_READ_WRITE" + ) + + check = calendar_external_sharing_primary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "EXTERNAL_ALL_INFO_READ_WRITE" in findings[0].status_extended + + def test_fail_no_policy_set(self): + """Test FAIL when no explicit policy is set (None) but fetch succeeded""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar import ( + calendar_external_sharing_primary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + primary_calendar_external_sharing=None + ) + + check = calendar_external_sharing_primary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "not explicitly configured" in findings[0].status_extended + + def test_no_findings_when_fetch_failed(self): + """Test no findings returned when the API fetch failed""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_primary_calendar.calendar_external_sharing_primary_calendar import ( + calendar_external_sharing_primary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = False + mock_calendar_client.policies = CalendarPolicies() + + check = calendar_external_sharing_primary_calendar() + findings = check.execute() + + assert len(findings) == 0 diff --git a/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar_test.py b/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar_test.py new file mode 100644 index 0000000000..800f9ab5f0 --- /dev/null +++ b/tests/providers/googleworkspace/services/calendar/calendar_external_sharing_secondary_calendar/calendar_external_sharing_secondary_calendar_test.py @@ -0,0 +1,161 @@ +from unittest.mock import patch + +from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + CalendarPolicies, +) +from tests.providers.googleworkspace.googleworkspace_fixtures import ( + CUSTOMER_ID, + DOMAIN, + set_mocked_googleworkspace_provider, +) + + +class TestCalendarExternalSharingSecondaryCalendar: + def test_pass_free_busy_only(self): + """Test PASS when external sharing is restricted to free/busy only""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar import ( + calendar_external_sharing_secondary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + secondary_calendar_external_sharing="EXTERNAL_FREE_BUSY_ONLY" + ) + + check = calendar_external_sharing_secondary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "PASS" + assert "free/busy information only" in findings[0].status_extended + assert findings[0].resource_name == DOMAIN + assert findings[0].customer_id == CUSTOMER_ID + + def test_fail_read_only(self): + """Test FAIL when external sharing allows read-only access""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar import ( + calendar_external_sharing_secondary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + secondary_calendar_external_sharing="EXTERNAL_ALL_INFO_READ_ONLY" + ) + + check = calendar_external_sharing_secondary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "EXTERNAL_ALL_INFO_READ_ONLY" in findings[0].status_extended + assert "free/busy information only" in findings[0].status_extended + + def test_fail_read_write_manage(self): + """Test FAIL when external sharing allows read-write-manage access""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar import ( + calendar_external_sharing_secondary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + secondary_calendar_external_sharing="EXTERNAL_ALL_INFO_READ_WRITE_MANAGE" + ) + + check = calendar_external_sharing_secondary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "EXTERNAL_ALL_INFO_READ_WRITE_MANAGE" in findings[0].status_extended + + def test_fail_no_policy_set(self): + """Test FAIL when no explicit policy is set (None) but fetch succeeded""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar import ( + calendar_external_sharing_secondary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = True + mock_calendar_client.policies = CalendarPolicies( + secondary_calendar_external_sharing=None + ) + + check = calendar_external_sharing_secondary_calendar() + findings = check.execute() + + assert len(findings) == 1 + assert findings[0].status == "FAIL" + assert "not explicitly configured" in findings[0].status_extended + + def test_no_findings_when_fetch_failed(self): + """Test no findings returned when the API fetch failed""" + mock_provider = set_mocked_googleworkspace_provider() + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar.calendar_client" + ) as mock_calendar_client, + ): + from prowler.providers.googleworkspace.services.calendar.calendar_external_sharing_secondary_calendar.calendar_external_sharing_secondary_calendar import ( + calendar_external_sharing_secondary_calendar, + ) + + mock_calendar_client.provider = mock_provider + mock_calendar_client.policies_fetched = False + mock_calendar_client.policies = CalendarPolicies() + + check = calendar_external_sharing_secondary_calendar() + findings = check.execute() + + assert len(findings) == 0 diff --git a/tests/providers/googleworkspace/services/calendar/calendar_service_test.py b/tests/providers/googleworkspace/services/calendar/calendar_service_test.py new file mode 100644 index 0000000000..1491f839fb --- /dev/null +++ b/tests/providers/googleworkspace/services/calendar/calendar_service_test.py @@ -0,0 +1,231 @@ +from unittest.mock import MagicMock, patch + +from tests.providers.googleworkspace.googleworkspace_fixtures import ( + set_mocked_googleworkspace_provider, +) + + +class TestCalendarService: + def test_calendar_fetch_policies_all_settings(self): + """Test fetching all 3 calendar policy settings from Cloud Identity API""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_credentials = MagicMock() + mock_session = MagicMock() + mock_session.credentials = mock_credentials + mock_provider.session = mock_session + + mock_service = MagicMock() + mock_policies_list = MagicMock() + # Mock the actual Cloud Identity Policy API v1 response shape: + # - "type" (not "name"), prefixed with "settings/" + # - inner value field names are camelCase + mock_policies_list.execute.return_value = { + "policies": [ + { + "setting": { + "type": "settings/calendar.primary_calendar_max_allowed_external_sharing", + "value": { + "maxAllowedExternalSharing": "EXTERNAL_FREE_BUSY_ONLY" + }, + } + }, + { + "setting": { + "type": "settings/calendar.secondary_calendar_max_allowed_external_sharing", + "value": { + "maxAllowedExternalSharing": "EXTERNAL_ALL_INFO_READ_ONLY" + }, + } + }, + { + "setting": { + "type": "settings/calendar.external_invitations", + "value": {"warnOnInvite": True}, + } + }, + ] + } + mock_service.policies().list.return_value = mock_policies_list + mock_service.policies().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, + ) + + calendar = Calendar(mock_provider) + + assert calendar.policies_fetched is True + assert ( + calendar.policies.primary_calendar_external_sharing + == "EXTERNAL_FREE_BUSY_ONLY" + ) + assert ( + calendar.policies.secondary_calendar_external_sharing + == "EXTERNAL_ALL_INFO_READ_ONLY" + ) + assert calendar.policies.external_invitations_warning is True + + def test_calendar_fetch_policies_empty_response(self): + """Test handling empty policies response""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + mock_policies_list = MagicMock() + mock_policies_list.execute.return_value = {"policies": []} + mock_service.policies().list.return_value = mock_policies_list + mock_service.policies().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, + ) + + calendar = Calendar(mock_provider) + + assert calendar.policies_fetched is True + assert calendar.policies.primary_calendar_external_sharing is None + assert calendar.policies.secondary_calendar_external_sharing is None + assert calendar.policies.external_invitations_warning is None + + def test_calendar_fetch_policies_api_error(self): + """Test handling of API errors during policy fetch""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + mock_service.policies().list.side_effect = Exception("API Error") + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, + ) + + calendar = Calendar(mock_provider) + + assert calendar.policies_fetched is False + assert calendar.policies.primary_calendar_external_sharing is None + assert calendar.policies.secondary_calendar_external_sharing is None + assert calendar.policies.external_invitations_warning is None + + def test_calendar_fetch_policies_build_service_returns_none(self): + """Test early return when _build_service fails to construct the client""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_service.GoogleWorkspaceService._build_service", + return_value=None, + ), + ): + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, + ) + + calendar = Calendar(mock_provider) + + assert calendar.policies_fetched is False + assert calendar.policies.primary_calendar_external_sharing is None + assert calendar.policies.secondary_calendar_external_sharing is None + assert calendar.policies.external_invitations_warning is None + + def test_calendar_fetch_policies_execute_raises(self): + """Test inner except handler when request.execute() raises during pagination""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + mock_request = MagicMock() + mock_request.execute.side_effect = Exception("Execute failed") + mock_service.policies().list.return_value = mock_request + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.calendar.calendar_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + Calendar, + ) + + calendar = Calendar(mock_provider) + + assert calendar.policies_fetched is False + assert calendar.policies.primary_calendar_external_sharing is None + assert calendar.policies.secondary_calendar_external_sharing is None + assert calendar.policies.external_invitations_warning is None + + def test_calendar_policies_model(self): + """Test CalendarPolicies Pydantic model""" + from prowler.providers.googleworkspace.services.calendar.calendar_service import ( + CalendarPolicies, + ) + + policies = CalendarPolicies( + primary_calendar_external_sharing="EXTERNAL_FREE_BUSY_ONLY", + secondary_calendar_external_sharing="EXTERNAL_ALL_INFO_READ_WRITE", + external_invitations_warning=True, + ) + + assert policies.primary_calendar_external_sharing == "EXTERNAL_FREE_BUSY_ONLY" + assert ( + policies.secondary_calendar_external_sharing + == "EXTERNAL_ALL_INFO_READ_WRITE" + ) + assert policies.external_invitations_warning is True From 406eedd68a54191119f0937a2f1a19a7adcf6bc8 Mon Sep 17 00:00:00 2001 From: "Pablo Fernandez Guerra (PFE)" <148432447+pfe-nazaries@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:27:12 +0200 Subject: [PATCH 07/36] chore(ui): unset GIT_WORK_TREE in pre-commit hook (#10574) Co-authored-by: Pablo F.G Co-authored-by: Claude Opus 4.6 (1M context) --- ui/.husky/pre-commit | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui/.husky/pre-commit b/ui/.husky/pre-commit index 98be29c453..0755cd1872 100755 --- a/ui/.husky/pre-commit +++ b/ui/.husky/pre-commit @@ -6,6 +6,12 @@ set -e +# The Python pre-commit framework (see .pre-commit-config.yaml, hook "ui-checks") +# exports GIT_WORK_TREE, GIT_DIR, and GIT_INDEX_FILE pointing to its temp staging +# area. Unset them so git commands below resolve against the real repo and index. +# See: https://github.com/prowler-cloud/prowler/pull/10574 +unset GIT_WORK_TREE GIT_DIR GIT_INDEX_FILE GIT_PREFIX GIT_COMMON_DIR GIT_OBJECT_DIRECTORY + # Colors RED='\033[0;31m' GREEN='\033[0;32m' From ad7a56d01007e7be05eefe0e2997ab73c1fbadbc Mon Sep 17 00:00:00 2001 From: Davidm4r Date: Thu, 9 Apr 2026 08:51:39 +0200 Subject: [PATCH 08/36] fix(ui): show active organization ID in profile page (#10617) --- ui/app/(prowler)/profile/page.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/app/(prowler)/profile/page.tsx b/ui/app/(prowler)/profile/page.tsx index 77cf9d50fc..c992734283 100644 --- a/ui/app/(prowler)/profile/page.tsx +++ b/ui/app/(prowler)/profile/page.tsx @@ -77,11 +77,7 @@ const SSRDataUser = async ({ {}, ); - const firstUserMembership = membershipsIncluded.find( - (m) => m.relationships?.user?.data?.id === userData.id, - ); - - const userTenantId = firstUserMembership?.relationships?.tenant?.data?.id; + const userTenantId = session?.tenantId; const userRoleIds = userData.relationships?.roles?.data?.map((r) => r.id) || []; From fcabe1f99ea7ae3f47d1d4c446bf66cdd04345f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:57:16 +0200 Subject: [PATCH 09/36] chore(deps): bump aiohttp from 3.13.3 to 3.13.5 (#10537) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Daniel Barranquero --- poetry.lock | 244 +++++++++++++++++++++---------------------- prowler/CHANGELOG.md | 1 + 2 files changed, 123 insertions(+), 122 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1206608902..a76112ff76 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "about-time" @@ -38,132 +38,132 @@ files = [ [[package]] name = "aiohttp" -version = "3.13.3" +version = "3.13.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, - {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, - {file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, - {file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, - {file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, - {file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, - {file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, - {file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, - {file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, - {file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, - {file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, - {file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, - {file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"}, - {file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"}, - {file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"}, - {file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"}, - {file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"}, - {file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7"}, + {file = "aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9"}, + {file = "aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3"}, + {file = "aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06"}, + {file = "aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14"}, + {file = "aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3"}, + {file = "aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c"}, + {file = "aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc"}, + {file = "aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b"}, + {file = "aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3"}, + {file = "aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b"}, + {file = "aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83"}, + {file = "aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67"}, + {file = "aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1"}, ] [package.dependencies] diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 56c363b9cf..cd5e995eae 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -45,6 +45,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Sensitive CLI flag values (tokens, keys, passwords) in HTML output "Parameters used" field now redacted to prevent credential leaks [(#10518)](https://github.com/prowler-cloud/prowler/pull/10518) - `authlib` bumped from 1.6.5 to 1.6.9 to fix CVE-2026-28802 (JWT `alg: none` validation bypass) [(#10579)](https://github.com/prowler-cloud/prowler/pull/10579) - `cryptography` bumped from 44.0.3 to 46.0.6 ([CVE-2026-26007](https://github.com/pyca/cryptography/security/advisories/GHSA-r6ph-v2qm-q3c2), [CVE-2026-34073](https://github.com/pyca/cryptography/security/advisories/GHSA-m959-cc7f-wv43)), `oci` to 2.169.0, and `alibabacloud-tea-openapi` to 0.4.4 [(#10535)](https://github.com/prowler-cloud/prowler/pull/10535) +- `aiohttp` bumped from 3.13.3 to 3.13.5 to fix CVE-2026-34520 (the C parser accepted null bytes and control characters in response headers) [(#10537)](https://github.com/prowler-cloud/prowler/pull/10537) --- From 379df7800d9ffc4599b3d1dfa8ce1128b7630d0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 09:27:55 +0200 Subject: [PATCH 10/36] chore(deps): bump aiohttp from 3.13.3 to 3.13.5 in /api (#10538) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Daniel Barranquero --- api/CHANGELOG.md | 1 + api/poetry.lock | 242 +++++++++++++++++++++++------------------------ 2 files changed, 122 insertions(+), 121 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 54b589e496..936ce9f6b3 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to the **Prowler API** are documented in this file. - Pin all unpinned dependencies to exact versions to prevent supply chain attacks and ensure reproducible builds [(#10469)](https://github.com/prowler-cloud/prowler/pull/10469) - `authlib` bumped from 1.6.6 to 1.6.9 to fix CVE-2026-28802 (JWT `alg: none` validation bypass) [(#10579)](https://github.com/prowler-cloud/prowler/pull/10579) +- `aiohttp` bumped from 3.13.3 to 3.13.5 to fix CVE-2026-34520 (the C parser accepted null bytes and control characters in response headers) [(#10538)](https://github.com/prowler-cloud/prowler/pull/10538) --- diff --git a/api/poetry.lock b/api/poetry.lock index 95f7cce24e..24fca80a26 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -103,132 +103,132 @@ files = [ [[package]] name = "aiohttp" -version = "3.13.3" +version = "3.13.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, - {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, - {file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, - {file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, - {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, - {file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, - {file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, - {file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, - {file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, - {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, - {file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, - {file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, - {file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, - {file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, - {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, - {file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, - {file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, - {file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, - {file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, - {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, - {file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, - {file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, - {file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, - {file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, - {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, - {file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, - {file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"}, - {file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"}, - {file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"}, - {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"}, - {file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"}, - {file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"}, - {file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"}, - {file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"}, - {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"}, - {file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"}, - {file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"}, - {file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7"}, + {file = "aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9"}, + {file = "aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3"}, + {file = "aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06"}, + {file = "aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14"}, + {file = "aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3"}, + {file = "aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c"}, + {file = "aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc"}, + {file = "aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b"}, + {file = "aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3"}, + {file = "aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b"}, + {file = "aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83"}, + {file = "aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67"}, + {file = "aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1"}, ] [package.dependencies] From b9270df3e6f664c0d9b807bbbfe7550c03c9f0d5 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Thu, 9 Apr 2026 09:39:52 +0200 Subject: [PATCH 11/36] feat(ui): improvements over findings groups feature (#10590) --- .../finding-groups.adapter.test.ts | 2 + .../finding-groups/finding-groups.adapter.ts | 4 +- .../finding-groups/finding-groups.test.ts | 174 +++++++----- ui/actions/finding-groups/finding-groups.ts | 203 +++++++------- ui/actions/findings/findings-by-resource.ts | 3 + ui/app/(prowler)/findings/page.test.ts | 37 +++ ui/app/(prowler)/findings/page.tsx | 46 ++-- ui/app/(prowler)/scans/page.tsx | 37 ++- ui/components/findings/findings-filters.tsx | 57 +--- .../findings/findings-filters.utils.test.ts | 148 +++++++++++ .../findings/findings-filters.utils.ts | 80 ++++++ .../table/column-finding-groups.test.tsx | 139 +++++++++- .../findings/table/column-finding-groups.tsx | 16 +- .../table/column-finding-resources.test.tsx | 203 ++++++++++++++ .../table/column-finding-resources.tsx | 24 +- .../table/finding-group-selection.test.ts | 45 ++++ .../findings/table/finding-group-selection.ts | 13 + .../table/finding-resource-selection.test.ts | 47 ++++ .../table/finding-resource-selection.ts | 5 + .../table/findings-group-drill-down.tsx | 11 +- .../findings/table/findings-group-table.tsx | 19 +- .../table/inline-resource-container.tsx | 9 +- .../resource-detail-drawer-content.test.tsx | 193 +++++++++++++- .../resource-detail-drawer-content.tsx | 166 ++++++++++-- .../resource-detail-skeleton.test.tsx | 26 ++ .../resource-detail-skeleton.tsx | 11 +- .../use-resource-detail-drawer.test.ts | 250 ++++++++++++++++++ .../use-resource-detail-drawer.ts | 64 ++++- ui/components/scans/scans-filters.tsx | 57 +++- ui/components/shadcn/card/card.tsx | 2 +- ui/components/ui/entities/date-with-time.tsx | 40 ++- ui/hooks/use-infinite-resources.test.ts | 32 +++ ui/hooks/use-infinite-resources.ts | 12 +- ui/lib/findings-scan-filters.test.ts | 112 ++++++++ ui/lib/findings-scan-filters.ts | 99 +++++++ ui/types/findings-table.ts | 2 + 36 files changed, 2061 insertions(+), 327 deletions(-) create mode 100644 ui/app/(prowler)/findings/page.test.ts create mode 100644 ui/components/findings/findings-filters.utils.test.ts create mode 100644 ui/components/findings/findings-filters.utils.ts create mode 100644 ui/components/findings/table/column-finding-resources.test.tsx create mode 100644 ui/components/findings/table/finding-group-selection.test.ts create mode 100644 ui/components/findings/table/finding-group-selection.ts create mode 100644 ui/components/findings/table/finding-resource-selection.test.ts create mode 100644 ui/components/findings/table/finding-resource-selection.ts create mode 100644 ui/components/findings/table/resource-detail-drawer/resource-detail-skeleton.test.tsx create mode 100644 ui/lib/findings-scan-filters.test.ts create mode 100644 ui/lib/findings-scan-filters.ts diff --git a/ui/actions/finding-groups/finding-groups.adapter.test.ts b/ui/actions/finding-groups/finding-groups.adapter.test.ts index 5874ddf7e5..1d5d04e62d 100644 --- a/ui/actions/finding-groups/finding-groups.adapter.test.ts +++ b/ui/actions/finding-groups/finding-groups.adapter.test.ts @@ -163,6 +163,7 @@ describe("adaptFindingGroupResourcesResponse โ€” malformed input", () => { alias: "production", }, status: "FAIL", + delta: "new", severity: "critical", first_seen_at: null, last_seen_at: "2024-01-01T00:00:00Z", @@ -178,5 +179,6 @@ describe("adaptFindingGroupResourcesResponse โ€” malformed input", () => { expect(result).toHaveLength(1); expect(result[0].checkId).toBe("s3_check"); expect(result[0].resourceName).toBe("my-bucket"); + expect(result[0].delta).toBe("new"); }); }); diff --git a/ui/actions/finding-groups/finding-groups.adapter.ts b/ui/actions/finding-groups/finding-groups.adapter.ts index 593171078d..2e3964522e 100644 --- a/ui/actions/finding-groups/finding-groups.adapter.ts +++ b/ui/actions/finding-groups/finding-groups.adapter.ts @@ -98,6 +98,7 @@ interface FindingGroupResourceAttributes { resource: ResourceInfo; provider: ProviderInfo; status: string; + delta?: string | null; severity: string; first_seen_at: string | null; last_seen_at: string | null; @@ -137,14 +138,15 @@ export function adaptFindingGroupResourcesResponse( providerAlias: item.attributes.provider?.alias || "", providerUid: item.attributes.provider?.uid || "", resourceName: item.attributes.resource?.name || "-", + resourceType: item.attributes.resource?.type || "-", resourceGroup: item.attributes.resource?.resource_group || "-", resourceUid: item.attributes.resource?.uid || "-", service: item.attributes.resource?.service || "-", region: item.attributes.resource?.region || "-", severity: (item.attributes.severity || "informational") as Severity, status: item.attributes.status, + delta: item.attributes.delta || null, isMuted: item.attributes.status === "MUTED", - // TODO: remove fallback once the API returns muted_reason in finding-group-resources mutedReason: item.attributes.muted_reason || undefined, firstSeenAt: item.attributes.first_seen_at, lastSeenAt: item.attributes.last_seen_at, diff --git a/ui/actions/finding-groups/finding-groups.test.ts b/ui/actions/finding-groups/finding-groups.test.ts index 0d8c2df53a..9f4bdc5830 100644 --- a/ui/actions/finding-groups/finding-groups.test.ts +++ b/ui/actions/finding-groups/finding-groups.test.ts @@ -47,10 +47,6 @@ import { getLatestFindingGroupResources, } from "./finding-groups"; -// --------------------------------------------------------------------------- -// Blocker 1 + 2: FAIL-first sort and FAIL-only filter for drill-down resources -// --------------------------------------------------------------------------- - // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- @@ -169,7 +165,7 @@ describe("getLatestFindingGroupResources โ€” SSRF path traversal protection", () }); // --------------------------------------------------------------------------- -// Blocker 1: Resources list must show FAIL first (sort=-status) +// Resources list keeps FAIL-first sort but no longer forces FAIL-only filtering // --------------------------------------------------------------------------- describe("getFindingGroupResources โ€” Blocker 1: FAIL-first sort", () => { @@ -181,30 +177,30 @@ describe("getFindingGroupResources โ€” Blocker 1: FAIL-first sort", () => { fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should include sort=-status in the API call so FAIL resources appear first", async () => { + it("should include the composite sort so FAIL resources appear first, then severity", async () => { // Given const checkId = "s3_bucket_public_access"; // When await getFindingGroupResources({ checkId }); - // Then โ€” the URL must contain sort=-status + // Then โ€” the URL must contain the composite sort const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.get("sort")).toBe("-status"); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); }); - it("should include filter[status]=FAIL in the API call so only impacted resources are shown", async () => { + it("should not force filter[status]=FAIL so PASS resources can also be shown", async () => { // Given const checkId = "s3_bucket_public_access"; // When await getFindingGroupResources({ checkId }); - // Then โ€” the URL must contain filter[status]=FAIL + // Then โ€” the URL should not add a hardcoded status filter const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.get("filter[status]")).toBe("FAIL"); + expect(url.searchParams.get("filter[status]")).toBeNull(); }); }); @@ -217,7 +213,7 @@ describe("getLatestFindingGroupResources โ€” Blocker 1: FAIL-first sort", () => fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should include sort=-status in the API call so FAIL resources appear first", async () => { + it("should include the composite sort so FAIL resources appear first, then severity", async () => { // Given const checkId = "iam_user_mfa_enabled"; @@ -227,10 +223,10 @@ describe("getLatestFindingGroupResources โ€” Blocker 1: FAIL-first sort", () => // Then const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.get("sort")).toBe("-status"); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); }); - it("should include filter[status]=FAIL in the API call so only impacted resources are shown", async () => { + it("should not force filter[status]=FAIL so PASS resources can also be shown", async () => { // Given const checkId = "iam_user_mfa_enabled"; @@ -240,7 +236,7 @@ describe("getLatestFindingGroupResources โ€” Blocker 1: FAIL-first sort", () => // Then const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.get("filter[status]")).toBe("FAIL"); + expect(url.searchParams.get("filter[status]")).toBeNull(); }); }); @@ -257,7 +253,7 @@ describe("getFindingGroupResources โ€” triangulation: params coexist", () => { fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should send sort=-status AND filter[status]=FAIL alongside pagination params", async () => { + it("should send the composite sort alongside pagination params without forcing filter[status]", async () => { // Given const checkId = "s3_bucket_versioning"; @@ -269,8 +265,8 @@ describe("getFindingGroupResources โ€” triangulation: params coexist", () => { const url = new URL(calledUrl); expect(url.searchParams.get("page[number]")).toBe("2"); expect(url.searchParams.get("page[size]")).toBe("50"); - expect(url.searchParams.get("sort")).toBe("-status"); - expect(url.searchParams.get("filter[status]")).toBe("FAIL"); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); + expect(url.searchParams.get("filter[status]")).toBeNull(); }); }); @@ -283,7 +279,7 @@ describe("getLatestFindingGroupResources โ€” triangulation: params coexist", () fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should send sort=-status AND filter[status]=FAIL alongside pagination params", async () => { + it("should send the composite sort alongside pagination params without forcing filter[status]", async () => { // Given const checkId = "iam_root_mfa_enabled"; @@ -295,16 +291,16 @@ describe("getLatestFindingGroupResources โ€” triangulation: params coexist", () const url = new URL(calledUrl); expect(url.searchParams.get("page[number]")).toBe("3"); expect(url.searchParams.get("page[size]")).toBe("20"); - expect(url.searchParams.get("sort")).toBe("-status"); - expect(url.searchParams.get("filter[status]")).toBe("FAIL"); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); + expect(url.searchParams.get("filter[status]")).toBeNull(); }); }); // --------------------------------------------------------------------------- -// Blocker: Duplicate filter[status] โ€” caller-supplied status must be stripped +// Caller filters should propagate unchanged to the drill-down resources endpoint // --------------------------------------------------------------------------- -describe("getFindingGroupResources โ€” Blocker: caller filter[status] is always overridden to FAIL", () => { +describe("getFindingGroupResources โ€” caller filters are preserved", () => { beforeEach(() => { vi.clearAllMocks(); vi.stubGlobal("fetch", fetchMock); @@ -313,23 +309,7 @@ describe("getFindingGroupResources โ€” Blocker: caller filter[status] is always fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should use filter[status]=FAIL even when caller passes filter[status]=PASS", async () => { - // Given โ€” caller explicitly passes PASS, which must be ignored - const checkId = "s3_bucket_public_access"; - const filters = { "filter[status]": "PASS" }; - - // When - await getFindingGroupResources({ checkId, filters }); - - // Then โ€” the final URL must have exactly one filter[status]=FAIL, not PASS - const calledUrl = fetchMock.mock.calls[0][0] as string; - const url = new URL(calledUrl); - const allStatusValues = url.searchParams.getAll("filter[status]"); - expect(allStatusValues).toHaveLength(1); - expect(allStatusValues[0]).toBe("FAIL"); - }); - - it("should not have duplicate filter[status] params when caller passes filter[status]", async () => { + it("should preserve caller filter[status] when explicitly provided", async () => { // Given const checkId = "s3_bucket_public_access"; const filters = { "filter[status]": "PASS" }; @@ -337,14 +317,56 @@ describe("getFindingGroupResources โ€” Blocker: caller filter[status] is always // When await getFindingGroupResources({ checkId, filters }); - // Then โ€” no duplicates + // Then const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.getAll("filter[status]")).toHaveLength(1); + const allStatusValues = url.searchParams.getAll("filter[status]"); + expect(allStatusValues).toHaveLength(1); + expect(allStatusValues[0]).toBe("PASS"); + }); + + it("should translate a single group status__in filter into filter[status] for resources", async () => { + // Given + const checkId = "s3_bucket_public_access"; + const filters = { + "filter[status__in]": "PASS", + "filter[severity__in]": "medium", + "filter[provider_type__in]": "aws", + }; + + // When + await getFindingGroupResources({ checkId, filters }); + + // Then + const calledUrl = fetchMock.mock.calls[0][0] as string; + const url = new URL(calledUrl); + expect(url.searchParams.get("filter[status]")).toBe("PASS"); + expect(url.searchParams.get("filter[status__in]")).toBeNull(); + expect(url.searchParams.get("filter[severity__in]")).toBe("medium"); + expect(url.searchParams.get("filter[provider_type__in]")).toBe("aws"); + }); + + it("should keep the composite sort when the resource search filter is applied", async () => { + // Given + const checkId = "s3_bucket_public_access"; + const filters = { + "filter[name__icontains]": "bucket-prod", + "filter[severity__in]": "high", + }; + + // When + await getFindingGroupResources({ checkId, filters }); + + // Then + const calledUrl = fetchMock.mock.calls[0][0] as string; + const url = new URL(calledUrl); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); + expect(url.searchParams.get("filter[name__icontains]")).toBe("bucket-prod"); + expect(url.searchParams.get("filter[severity__in]")).toBe("high"); }); }); -describe("getLatestFindingGroupResources โ€” Blocker: caller filter[status] is always overridden to FAIL", () => { +describe("getLatestFindingGroupResources โ€” caller filters are preserved", () => { beforeEach(() => { vi.clearAllMocks(); vi.stubGlobal("fetch", fetchMock); @@ -353,23 +375,7 @@ describe("getLatestFindingGroupResources โ€” Blocker: caller filter[status] is a fetchMock.mockResolvedValue(new Response("", { status: 200 })); }); - it("should use filter[status]=FAIL even when caller passes filter[status]=PASS", async () => { - // Given โ€” caller explicitly passes PASS, which must be ignored - const checkId = "iam_user_mfa_enabled"; - const filters = { "filter[status]": "PASS" }; - - // When - await getLatestFindingGroupResources({ checkId, filters }); - - // Then โ€” the final URL must have exactly one filter[status]=FAIL, not PASS - const calledUrl = fetchMock.mock.calls[0][0] as string; - const url = new URL(calledUrl); - const allStatusValues = url.searchParams.getAll("filter[status]"); - expect(allStatusValues).toHaveLength(1); - expect(allStatusValues[0]).toBe("FAIL"); - }); - - it("should not have duplicate filter[status] params when caller passes filter[status]", async () => { + it("should preserve caller filter[status] when explicitly provided", async () => { // Given const checkId = "iam_user_mfa_enabled"; const filters = { "filter[status]": "PASS" }; @@ -377,9 +383,53 @@ describe("getLatestFindingGroupResources โ€” Blocker: caller filter[status] is a // When await getLatestFindingGroupResources({ checkId, filters }); - // Then โ€” no duplicates + // Then const calledUrl = fetchMock.mock.calls[0][0] as string; const url = new URL(calledUrl); - expect(url.searchParams.getAll("filter[status]")).toHaveLength(1); + const allStatusValues = url.searchParams.getAll("filter[status]"); + expect(allStatusValues).toHaveLength(1); + expect(allStatusValues[0]).toBe("PASS"); + }); + + it("should translate a single group status__in filter into filter[status] for latest resources", async () => { + // Given + const checkId = "iam_user_mfa_enabled"; + const filters = { + "filter[status__in]": "PASS", + "filter[severity__in]": "low", + "filter[provider_type__in]": "aws", + }; + + // When + await getLatestFindingGroupResources({ checkId, filters }); + + // Then + const calledUrl = fetchMock.mock.calls[0][0] as string; + const url = new URL(calledUrl); + expect(url.searchParams.get("filter[status]")).toBe("PASS"); + expect(url.searchParams.get("filter[status__in]")).toBeNull(); + expect(url.searchParams.get("filter[severity__in]")).toBe("low"); + expect(url.searchParams.get("filter[provider_type__in]")).toBe("aws"); + }); + + it("should keep the composite sort when the resource search filter is applied", async () => { + // Given + const checkId = "iam_user_mfa_enabled"; + const filters = { + "filter[name__icontains]": "instance-prod", + "filter[status__in]": "PASS,FAIL", + }; + + // When + await getLatestFindingGroupResources({ checkId, filters }); + + // Then + const calledUrl = fetchMock.mock.calls[0][0] as string; + const url = new URL(calledUrl); + expect(url.searchParams.get("sort")).toBe("-severity,-delta,-last_seen_at"); + expect(url.searchParams.get("filter[name__icontains]")).toBe( + "instance-prod", + ); + expect(url.searchParams.get("filter[status__in]")).toBe("PASS,FAIL"); }); }); diff --git a/ui/actions/finding-groups/finding-groups.ts b/ui/actions/finding-groups/finding-groups.ts index b31d7a5bfc..b08293c882 100644 --- a/ui/actions/finding-groups/finding-groups.ts +++ b/ui/actions/finding-groups/finding-groups.ts @@ -23,17 +23,68 @@ function mapSearchFilter( return mapped; } -export const getFindingGroups = async ({ - page = 1, - pageSize = 10, - sort = "", - filters = {}, -}) => { +function splitCsvFilterValues(value: string | string[] | undefined): string[] { + if (Array.isArray(value)) { + return value + .flatMap((item) => item.split(",")) + .map((item) => item.trim()) + .filter(Boolean); + } + + if (typeof value === "string") { + return value + .split(",") + .map((item) => item.trim()) + .filter(Boolean); + } + + return []; +} + +function normalizeFindingGroupResourceFilters( + filters: Record, +): Record { + const normalized = { ...filters }; + const exactStatusFilter = normalized["filter[status]"]; + + if (exactStatusFilter !== undefined) { + delete normalized["filter[status__in]"]; + return normalized; + } + + const statusValues = splitCsvFilterValues(normalized["filter[status__in]"]); + if (statusValues.length === 1) { + normalized["filter[status]"] = statusValues[0]; + delete normalized["filter[status__in]"]; + } + + return normalized; +} + +const DEFAULT_FINDING_GROUPS_SORT = + "-severity,-delta,-fail_count,-last_seen_at"; + +interface FetchFindingGroupsParams { + page?: number; + pageSize?: number; + sort?: string; + filters?: Record; +} + +async function fetchFindingGroupsEndpoint( + endpoint: string, + { + page = 1, + pageSize = 10, + sort = DEFAULT_FINDING_GROUPS_SORT, + filters = {}, + }: FetchFindingGroupsParams, +) { const headers = await getAuthHeaders({ contentType: false }); if (isNaN(Number(page)) || page < 1) redirect("/findings"); - const url = new URL(`${apiBaseUrl}/finding-groups`); + const url = new URL(`${apiBaseUrl}/${endpoint}`); if (page) url.searchParams.append("page[number]", page.toString()); if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); @@ -45,120 +96,60 @@ export const getFindingGroups = async ({ const response = await fetch(url.toString(), { headers }); return handleApiResponse(response); } catch (error) { - console.error("Error fetching finding groups:", error); + console.error(`Error fetching ${endpoint}:`, error); return undefined; } -}; +} -export const getLatestFindingGroups = async ({ - page = 1, - pageSize = 10, - sort = "", - filters = {}, -}) => { +export const getFindingGroups = async (params: FetchFindingGroupsParams = {}) => + fetchFindingGroupsEndpoint("finding-groups", params); + +export const getLatestFindingGroups = async ( + params: FetchFindingGroupsParams = {}, +) => fetchFindingGroupsEndpoint("finding-groups/latest", params); + +interface FetchFindingGroupResourcesParams { + checkId: string; + page?: number; + pageSize?: number; + filters?: Record; +} + +async function fetchFindingGroupResourcesEndpoint( + endpointPrefix: string, + { + checkId, + page = 1, + pageSize = 20, + filters = {}, + }: FetchFindingGroupResourcesParams, +) { const headers = await getAuthHeaders({ contentType: false }); + const normalizedFilters = normalizeFindingGroupResourceFilters(filters); - if (isNaN(Number(page)) || page < 1) redirect("/findings"); - - const url = new URL(`${apiBaseUrl}/finding-groups/latest`); + const url = new URL( + `${apiBaseUrl}/${endpointPrefix}/${encodeURIComponent(checkId)}/resources`, + ); if (page) url.searchParams.append("page[number]", page.toString()); if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); - if (sort) url.searchParams.append("sort", sort); + url.searchParams.append("sort", "-severity,-delta,-last_seen_at"); - appendSanitizedProviderFilters(url, mapSearchFilter(filters)); + appendSanitizedProviderFilters(url, normalizedFilters); try { const response = await fetch(url.toString(), { headers }); return handleApiResponse(response); } catch (error) { - console.error("Error fetching latest finding groups:", error); + console.error(`Error fetching ${endpointPrefix} resources:`, error); return undefined; } -}; +} -export const getFindingGroupResources = async ({ - checkId, - page = 1, - pageSize = 20, - filters = {}, -}: { - checkId: string; - page?: number; - pageSize?: number; - filters?: Record; -}) => { - const headers = await getAuthHeaders({ contentType: false }); +export const getFindingGroupResources = async ( + params: FetchFindingGroupResourcesParams, +) => fetchFindingGroupResourcesEndpoint("finding-groups", params); - const url = new URL( - `${apiBaseUrl}/finding-groups/${encodeURIComponent(checkId)}/resources`, - ); - - if (page) url.searchParams.append("page[number]", page.toString()); - if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); - // sort=-status is kept for future-proofing: if the filter[status]=FAIL - // constraint is ever relaxed to allow multiple statuses, the sort ensures - // FAIL resources still appear first in the result set. - url.searchParams.append("sort", "-status"); - - appendSanitizedProviderFilters(url, filters); - - // Use .set() AFTER appendSanitizedProviderFilters so our hardcoded FAIL - // always wins, even if the caller passed a different filter[status] value. - // Using .set() instead of .append() prevents duplicate filter[status] params. - url.searchParams.set("filter[status]", "FAIL"); - - try { - const response = await fetch(url.toString(), { - headers, - }); - - return handleApiResponse(response); - } catch (error) { - console.error("Error fetching finding group resources:", error); - return undefined; - } -}; - -export const getLatestFindingGroupResources = async ({ - checkId, - page = 1, - pageSize = 20, - filters = {}, -}: { - checkId: string; - page?: number; - pageSize?: number; - filters?: Record; -}) => { - const headers = await getAuthHeaders({ contentType: false }); - - const url = new URL( - `${apiBaseUrl}/finding-groups/latest/${encodeURIComponent(checkId)}/resources`, - ); - - if (page) url.searchParams.append("page[number]", page.toString()); - if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); - // sort=-status is kept for future-proofing: if the filter[status]=FAIL - // constraint is ever relaxed to allow multiple statuses, the sort ensures - // FAIL resources still appear first in the result set. - url.searchParams.append("sort", "-status"); - - appendSanitizedProviderFilters(url, filters); - - // Use .set() AFTER appendSanitizedProviderFilters so our hardcoded FAIL - // always wins, even if the caller passed a different filter[status] value. - // Using .set() instead of .append() prevents duplicate filter[status] params. - url.searchParams.set("filter[status]", "FAIL"); - - try { - const response = await fetch(url.toString(), { - headers, - }); - - return handleApiResponse(response); - } catch (error) { - console.error("Error fetching latest finding group resources:", error); - return undefined; - } -}; +export const getLatestFindingGroupResources = async ( + params: FetchFindingGroupResourcesParams, +) => fetchFindingGroupResourcesEndpoint("finding-groups/latest", params); diff --git a/ui/actions/findings/findings-by-resource.ts b/ui/actions/findings/findings-by-resource.ts index 12900ffdca..4c69d2e5ef 100644 --- a/ui/actions/findings/findings-by-resource.ts +++ b/ui/actions/findings/findings-by-resource.ts @@ -379,6 +379,9 @@ export const getLatestFindingsByResourceUid = async ({ ); url.searchParams.append("filter[resource_uid]", resourceUid); + url.searchParams.append("filter[status]", "FAIL"); + url.searchParams.append("filter[muted]", "include"); + url.searchParams.append("sort", "-severity,status,-updated_at"); if (page) url.searchParams.append("page[number]", page.toString()); if (pageSize) url.searchParams.append("page[size]", pageSize.toString()); diff --git a/ui/app/(prowler)/findings/page.test.ts b/ui/app/(prowler)/findings/page.test.ts new file mode 100644 index 0000000000..76462dff99 --- /dev/null +++ b/ui/app/(prowler)/findings/page.test.ts @@ -0,0 +1,37 @@ +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { describe, expect, it } from "vitest"; + +/** + * Source-level assertions for the findings page. + * + * Directly importing page.tsx triggers deep transitive imports + * (next-auth โ†’ next/server) that vitest cannot resolve without the + * full Next.js build pipeline. These tests verify key architectural + * invariants via source analysis instead. + */ +describe("findings page", () => { + const currentDir = path.dirname(fileURLToPath(import.meta.url)); + const pagePath = path.join(currentDir, "page.tsx"); + const source = readFileSync(pagePath, "utf8"); + + it("only passes sort to fetchFindingGroups when the user has an explicit sort param", () => { + expect(source).toContain("...(encodedSort && { sort: encodedSort })"); + }); + + it("normalizes scan filters with the required inserted_at params before fetching historical finding groups", () => { + expect(source).toContain("resolveFindingScanDateFilters"); + }); + + it("uses getLatestFindingGroups for non-date/scan queries and getFindingGroups for historical", () => { + expect(source).toContain("hasDateOrScan"); + expect(source).toContain("getFindingGroups"); + expect(source).toContain("getLatestFindingGroups"); + }); + + it("guards errors array access with a length check", () => { + expect(source).toContain("errors?.length > 0"); + }); +}); diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index 576d34ca1e..46749b38c2 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -7,7 +7,7 @@ import { } from "@/actions/finding-groups"; import { getLatestMetadataInfo, getMetadataInfo } from "@/actions/findings"; import { getProviders } from "@/actions/providers"; -import { getScans } from "@/actions/scans"; +import { getScan, getScans } from "@/actions/scans"; import { FindingsFilters } from "@/components/findings/findings-filters"; import { FindingsGroupTable, @@ -21,6 +21,7 @@ import { extractSortAndKey, hasDateOrScanFilter, } from "@/lib"; +import { resolveFindingScanDateFilters } from "@/lib/findings-scan-filters"; import { ScanEntity, ScanProps } from "@/types"; import { SearchParamsProps } from "@/types/components"; @@ -39,16 +40,28 @@ export default async function Findings({ // TODO: Re-implement deep link support (/findings?id=) using the grouped view's resource detail drawer // once the legacy FindingDetailsSheet is fully deprecated (still used by /resources and overview dashboard). - const [metadataInfoData, providersData, scansData] = await Promise.all([ - (hasDateOrScan ? getMetadataInfo : getLatestMetadataInfo)({ - query, - sort: encodedSort, - filters, - }), + const [providersData, scansData] = await Promise.all([ getProviders({ pageSize: 50 }), getScans({ pageSize: 50 }), ]); + const filtersWithScanDates = await resolveFindingScanDateFilters({ + filters, + scans: scansData?.data || [], + loadScan: async (scanId: string) => { + const response = await getScan(scanId); + return response?.data; + }, + }); + + const metadataInfoData = await ( + hasDateOrScan ? getMetadataInfo : getLatestMetadataInfo + )({ + query, + sort: encodedSort, + filters: filtersWithScanDates, + }); + // Extract unique regions, services, categories, groups from the new endpoint const uniqueRegions = metadataInfoData?.data?.attributes?.regions || []; const uniqueServices = metadataInfoData?.data?.attributes?.services || []; @@ -88,7 +101,10 @@ export default async function Findings({ /> }> - + @@ -97,19 +113,15 @@ export default async function Findings({ const SSRDataTable = async ({ searchParams, + filters, }: { searchParams: SearchParamsProps; + filters: Record; }) => { const page = parseInt(searchParams.page?.toString() || "1", 10); const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10); - const defaultSort = "-severity,-fail_count,-last_seen_at"; - const { encodedSort } = extractSortAndKey({ - ...searchParams, - sort: searchParams.sort ?? defaultSort, - }); - - const { filters } = extractFiltersAndQuery(searchParams); + const { encodedSort } = extractSortAndKey(searchParams); // Check if the searchParams contain any date or scan filter const hasDateOrScan = hasDateOrScanFilter(searchParams); @@ -119,7 +131,7 @@ const SSRDataTable = async ({ const findingGroupsData = await fetchFindingGroups({ page, - sort: encodedSort, + ...(encodedSort && { sort: encodedSort }), filters, pageSize, }); @@ -131,7 +143,7 @@ const SSRDataTable = async ({ return ( <> - {findingGroupsData?.errors && ( + {findingGroupsData?.errors?.length > 0 && (

Error:

{findingGroupsData.errors[0].detail}

diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx index 2d0416f37c..55dbf7eb8a 100644 --- a/ui/app/(prowler)/scans/page.tsx +++ b/ui/app/(prowler)/scans/page.tsx @@ -18,7 +18,12 @@ import { createProviderDetailsMapping, extractProviderUIDs, } from "@/lib/provider-helpers"; -import { ProviderProps, ScanProps, SearchParamsProps } from "@/types"; +import { + ExpandedScanData, + ProviderProps, + ScanProps, + SearchParamsProps, +} from "@/types"; export default async function Scans({ searchParams, @@ -30,7 +35,34 @@ export default async function Scans({ const filteredParams = { ...resolvedSearchParams }; delete filteredParams.scanId; - const providersData = await getAllProviders(); + const [providersData, completedScansData] = await Promise.all([ + getAllProviders(), + getScans({ + filters: { "filter[state]": "completed" }, + pageSize: 50, + fields: { scans: "name,completed_at,provider" }, + include: "provider", + }), + ]); + + const completedScans: ExpandedScanData[] = (completedScansData?.data ?? []) + .map((scan: ScanProps) => { + const providerId = scan.relationships?.provider?.data?.id; + const providerData = completedScansData?.included?.find( + (item: { type: string; id: string }) => + item.type === "providers" && item.id === providerId, + ); + if (!providerData) return null; + return { + ...scan, + providerInfo: { + provider: providerData.attributes.provider, + uid: providerData.attributes.uid, + alias: providerData.attributes.alias, + }, + }; + }) + .filter(Boolean) as ExpandedScanData[]; const providerInfo = providersData?.data @@ -90,6 +122,7 @@ export default async function Scans({
diff --git a/ui/components/findings/findings-filters.tsx b/ui/components/findings/findings-filters.tsx index af169bfcc1..526b6240f3 100644 --- a/ui/components/findings/findings-filters.tsx +++ b/ui/components/findings/findings-filters.tsx @@ -18,11 +18,12 @@ import { Button } from "@/components/shadcn"; import { ExpandableSection } from "@/components/ui/expandable-section"; import { DataTableFilterCustom } from "@/components/ui/table"; import { useFilterBatch } from "@/hooks/use-filter-batch"; -import { formatLabel, getCategoryLabel, getGroupLabel } from "@/lib/categories"; -import { FilterType, FINDING_STATUS_DISPLAY_NAMES, ScanEntity } from "@/types"; +import { getCategoryLabel, getGroupLabel } from "@/lib/categories"; +import { FilterType, ScanEntity } from "@/types"; import { DATA_TABLE_FILTER_MODE, FilterParam } from "@/types/filters"; -import { getProviderDisplayName, ProviderProps } from "@/types/providers"; -import { SEVERITY_DISPLAY_NAMES } from "@/types/severities"; +import { ProviderProps } from "@/types/providers"; + +import { getFindingsFilterDisplayValue } from "./findings-filters.utils"; interface FindingsFiltersProps { /** Provider data for ProviderTypeSelector and AccountsSelector */ @@ -58,49 +59,6 @@ const FILTER_KEY_LABELS: Record = { "filter[muted]": "Muted", }; -/** - * Formats a raw filter value into a human-readable display string. - * - Provider types: uses shared getProviderDisplayName utility - * - Severities: uses shared SEVERITY_DISPLAY_NAMES (e.g. "critical" โ†’ "Critical") - * - Status: uses shared FINDING_STATUS_DISPLAY_NAMES (e.g. "FAIL" โ†’ "Fail") - * - Categories: uses getCategoryLabel (handles IAM, EC2, IMDSv1, etc.) - * - Resource groups: uses getGroupLabel (underscore-delimited) - * - Date (filter[inserted_at]): returns the ISO date string as-is (YYYY-MM-DD) - * - Other values: uses formatLabel as a generic fallback (avoids naive capitalisation) - */ -const formatFilterValue = (filterKey: string, value: string): string => { - if (!value) return value; - if (filterKey === "filter[provider_type__in]") { - return getProviderDisplayName(value); - } - if (filterKey === "filter[severity__in]") { - return ( - SEVERITY_DISPLAY_NAMES[ - value.toLowerCase() as keyof typeof SEVERITY_DISPLAY_NAMES - ] ?? formatLabel(value) - ); - } - if (filterKey === "filter[status__in]") { - return ( - FINDING_STATUS_DISPLAY_NAMES[ - value as keyof typeof FINDING_STATUS_DISPLAY_NAMES - ] ?? formatLabel(value) - ); - } - if (filterKey === "filter[category__in]") { - return getCategoryLabel(value); - } - if (filterKey === "filter[resource_groups__in]") { - return getGroupLabel(value); - } - // Date filter: preserve ISO date string (YYYY-MM-DD) โ€” do not run through formatLabel - if (filterKey === "filter[inserted_at]") { - return value; - } - // Generic fallback: handles hyphen/underscore-delimited IDs with smart capitalisation - return formatLabel(value); -}; - export const FindingsFilters = ({ providers, completedScanIds, @@ -185,7 +143,10 @@ export const FindingsFilters = ({ key, label, value, - displayValue: formatFilterValue(key, value), + displayValue: getFindingsFilterDisplayValue(key, value, { + providers, + scans: scanDetails, + }), }); }); }); diff --git a/ui/components/findings/findings-filters.utils.test.ts b/ui/components/findings/findings-filters.utils.test.ts new file mode 100644 index 0000000000..86a3124b0a --- /dev/null +++ b/ui/components/findings/findings-filters.utils.test.ts @@ -0,0 +1,148 @@ +import { describe, expect, it } from "vitest"; + +import { ProviderProps } from "@/types/providers"; +import { ScanEntity } from "@/types/scans"; + +import { getFindingsFilterDisplayValue } from "./findings-filters.utils"; + +function makeProvider( + overrides: Partial & { id: string }, +): ProviderProps { + return { + type: "providers", + attributes: { + provider: "aws", + uid: "123456789012", + alias: "Production Account", + status: "completed", + resources: 10, + connection: { connected: true, last_checked_at: "2026-04-07T10:00:00Z" }, + scanner_args: { + only_logs: false, + excluded_checks: [], + aws_retries_max_attempts: 3, + }, + inserted_at: "2026-04-07T10:00:00Z", + updated_at: "2026-04-07T10:00:00Z", + created_by: { object: "user", id: "user-1" }, + }, + relationships: { + secret: { data: null }, + provider_groups: { meta: { count: 0 }, data: [] }, + }, + ...overrides, + } as ProviderProps; +} + +function makeScanMap( + scanId: string, + overrides?: Partial, +): { [scanId: string]: ScanEntity } { + return { + [scanId]: { + id: scanId, + providerInfo: { + provider: "aws", + alias: "Scan Account", + uid: "123456789012", + }, + attributes: { + name: "Nightly scan", + completed_at: "2026-04-07T10:00:00Z", + }, + ...overrides, + }, + }; +} + +const providers = [makeProvider({ id: "provider-1" })]; +const scans = [makeScanMap("scan-1")]; + +describe("getFindingsFilterDisplayValue", () => { + it("shows the account alias for provider_id filters instead of the raw provider id", () => { + expect( + getFindingsFilterDisplayValue("filter[provider_id__in]", "provider-1", { + providers, + }), + ).toBe("Production Account"); + }); + + it("falls back to the provider uid when the alias is empty", () => { + expect( + getFindingsFilterDisplayValue("filter[provider_id__in]", "provider-2", { + providers: [ + ...providers, + makeProvider({ + id: "provider-2", + attributes: { + ...providers[0].attributes, + alias: "", + uid: "210987654321", + }, + }), + ], + }), + ).toBe("210987654321"); + }); + + it("keeps the raw value when the provider cannot be resolved", () => { + expect( + getFindingsFilterDisplayValue( + "filter[provider_id__in]", + "missing-provider", + { providers }, + ), + ).toBe("missing-provider"); + }); + + it("shows the resolved scan badge label for scan filters instead of formatting the raw scan id", () => { + expect( + getFindingsFilterDisplayValue("filter[scan__in]", "scan-1", { scans }), + ).toBe("Scan Account"); + }); + + it("falls back to the scan provider uid when the alias is missing", () => { + expect( + getFindingsFilterDisplayValue("filter[scan__in]", "scan-2", { + scans: [ + ...scans, + makeScanMap("scan-2", { + providerInfo: { provider: "aws", uid: "210987654321" }, + attributes: { + name: "Weekly scan", + completed_at: "2026-04-08T10:00:00Z", + }, + }), + ], + }), + ).toBe("210987654321"); + }); + + it("keeps the raw scan value when the scan cannot be resolved", () => { + expect( + getFindingsFilterDisplayValue("filter[scan__in]", "missing-scan", { + scans, + }), + ).toBe("missing-scan"); + }); + + it("passes through date values for inserted_at__gte filters", () => { + expect( + getFindingsFilterDisplayValue( + "filter[inserted_at__gte]", + "2026-04-03", + {}, + ), + ).toBe("2026-04-03"); + }); + + it("passes through date values for inserted_at__lte filters", () => { + expect( + getFindingsFilterDisplayValue( + "filter[inserted_at__lte]", + "2026-04-07", + {}, + ), + ).toBe("2026-04-07"); + }); +}); diff --git a/ui/components/findings/findings-filters.utils.ts b/ui/components/findings/findings-filters.utils.ts new file mode 100644 index 0000000000..6cb9c19b28 --- /dev/null +++ b/ui/components/findings/findings-filters.utils.ts @@ -0,0 +1,80 @@ +import { formatLabel, getCategoryLabel, getGroupLabel } from "@/lib/categories"; +import { FINDING_STATUS_DISPLAY_NAMES } from "@/types"; +import { getProviderDisplayName, ProviderProps } from "@/types/providers"; +import { ScanEntity } from "@/types/scans"; +import { SEVERITY_DISPLAY_NAMES } from "@/types/severities"; + +interface GetFindingsFilterDisplayValueOptions { + providers?: ProviderProps[]; + scans?: Array<{ [scanId: string]: ScanEntity }>; +} + +function getProviderAccountDisplayValue( + providerId: string, + providers: ProviderProps[], +): string { + const provider = providers.find((item) => item.id === providerId); + if (!provider) { + return providerId; + } + + return provider.attributes.alias || provider.attributes.uid || providerId; +} + +function getScanDisplayValue( + scanId: string, + scans: Array<{ [scanId: string]: ScanEntity }>, +): string { + const scan = scans.find((item) => item[scanId])?.[scanId]; + if (!scan) { + return scanId; + } + + return scan.providerInfo.alias || scan.providerInfo.uid || scanId; +} + +export function getFindingsFilterDisplayValue( + filterKey: string, + value: string, + options: GetFindingsFilterDisplayValueOptions = {}, +): string { + if (!value) return value; + if (filterKey === "filter[provider_type__in]") { + return getProviderDisplayName(value); + } + if (filterKey === "filter[provider_id__in]") { + return getProviderAccountDisplayValue(value, options.providers || []); + } + if (filterKey === "filter[scan__in]") { + return getScanDisplayValue(value, options.scans || []); + } + if (filterKey === "filter[severity__in]") { + return ( + SEVERITY_DISPLAY_NAMES[ + value.toLowerCase() as keyof typeof SEVERITY_DISPLAY_NAMES + ] ?? formatLabel(value) + ); + } + if (filterKey === "filter[status__in]") { + return ( + FINDING_STATUS_DISPLAY_NAMES[ + value as keyof typeof FINDING_STATUS_DISPLAY_NAMES + ] ?? formatLabel(value) + ); + } + if (filterKey === "filter[category__in]") { + return getCategoryLabel(value); + } + if (filterKey === "filter[resource_groups__in]") { + return getGroupLabel(value); + } + if ( + filterKey === "filter[inserted_at]" || + filterKey === "filter[inserted_at__gte]" || + filterKey === "filter[inserted_at__lte]" + ) { + return value; + } + + return formatLabel(value); +} diff --git a/ui/components/findings/table/column-finding-groups.test.tsx b/ui/components/findings/table/column-finding-groups.test.tsx index ab5d26bc62..e723e51862 100644 --- a/ui/components/findings/table/column-finding-groups.test.tsx +++ b/ui/components/findings/table/column-finding-groups.test.tsx @@ -17,11 +17,20 @@ vi.mock("next/navigation", () => ({ vi.mock("@/components/shadcn", () => ({ Checkbox: ({ "aria-label": ariaLabel, + onCheckedChange, ...props }: InputHTMLAttributes & { "aria-label"?: string; size?: string; - }) => , + onCheckedChange?: (checked: boolean) => void; + }) => ( + onCheckedChange?.(event.target.checked)} + {...props} + /> + ), })); vi.mock("@/components/ui/table", () => ({ @@ -52,7 +61,13 @@ vi.mock("./impacted-providers-cell", () => ({ })); vi.mock("./impacted-resources-cell", () => ({ - ImpactedResourcesCell: () => null, + ImpactedResourcesCell: ({ + impacted, + total, + }: { + impacted: number; + total: number; + }) => {`${impacted}/${total}`}, })); vi.mock("./notification-indicator", () => ({ @@ -94,6 +109,7 @@ function makeGroup(overrides?: Partial): FindingGroupRow { function renderFindingCell( checkTitle: string, onDrillDown: (checkId: string, group: FindingGroupRow) => void, + overrides?: Partial, ) { const columns = getColumnFindingGroups({ rowSelection: {}, @@ -107,7 +123,7 @@ function renderFindingCell( ); if (!findingColumn?.cell) throw new Error("finding column not found"); - const group = makeGroup({ checkTitle }); + const group = makeGroup({ checkTitle, ...overrides }); // Render the cell directly with a minimal row mock const CellComponent = findingColumn.cell as (props: { row: { original: FindingGroupRow }; @@ -116,6 +132,67 @@ function renderFindingCell( render(
{CellComponent({ row: { original: group } })}
); } +function renderImpactedResourcesCell(overrides?: Partial) { + const columns = getColumnFindingGroups({ + rowSelection: {}, + selectableRowCount: 1, + onDrillDown: vi.fn(), + }); + + const impactedResourcesColumn = columns.find( + (col) => (col as { id?: string }).id === "impactedResources", + ); + if (!impactedResourcesColumn?.cell) { + throw new Error("impactedResources column not found"); + } + + const group = makeGroup(overrides); + const CellComponent = impactedResourcesColumn.cell as (props: { + row: { original: FindingGroupRow }; + }) => ReactNode; + + render(
{CellComponent({ row: { original: group } })}
); +} + +function renderSelectCell(overrides?: Partial) { + const toggleSelected = vi.fn(); + const columns = getColumnFindingGroups({ + rowSelection: {}, + selectableRowCount: 1, + onDrillDown: vi.fn(), + }); + + const selectColumn = columns.find( + (col) => (col as { id?: string }).id === "select", + ); + if (!selectColumn?.cell) { + throw new Error("select column not found"); + } + + const group = makeGroup(overrides); + const CellComponent = selectColumn.cell as (props: { + row: { + id: string; + original: FindingGroupRow; + toggleSelected: (selected: boolean) => void; + }; + }) => ReactNode; + + render( +
+ {CellComponent({ + row: { + id: "0", + original: group, + toggleSelected, + }, + })} +
, + ); + + return { toggleSelected }; +} + // --------------------------------------------------------------------------- // Fix 5: Accessibility โ€”

โ†’ + ), +})); + +vi.mock("@/components/shadcn/info-field/info-field", () => ({ + InfoField: () => null, +})); + +vi.mock("@/components/shadcn/spinner/spinner", () => ({ + Spinner: () => null, +})); + +vi.mock("@/components/ui/entities", () => ({ + DateWithTime: () => null, +})); + +vi.mock("@/components/ui/entities/entity-info", () => ({ + EntityInfo: ({ + entityAlias, + entityId, + }: { + entityAlias?: string; + entityId?: string; + }) => ( +

+ {entityAlias} + {entityId} +
+ ), +})); + +vi.mock("@/components/ui/table", () => ({ + SeverityBadge: ({ severity }: { severity: string }) => ( + {severity} + ), +})); + +vi.mock("@/components/ui/table/data-table-column-header", () => ({ + DataTableColumnHeader: ({ title }: { title: string }) => {title}, +})); + +vi.mock("@/components/ui/table/status-finding-badge", () => ({ + StatusFindingBadge: ({ status }: { status: string }) => {status}, +})); + +vi.mock("@/lib/date-utils", () => ({ + getFailingForLabel: () => "2d", +})); + +const notificationIndicatorMock = vi.fn((_props: unknown) => null); + +vi.mock("./notification-indicator", () => ({ + NotificationIndicator: (props: unknown) => { + notificationIndicatorMock(props); + return null; + }, +})); + +import type { FindingResourceRow } from "@/types"; + +import { getColumnFindingResources } from "./column-finding-resources"; + +function makeResource( + overrides?: Partial, +): FindingResourceRow { + return { + id: "resource-row-1", + rowType: "resource", + findingId: "finding-1", + checkId: "s3_check", + providerType: "aws", + providerAlias: "production", + providerUid: "123456789", + resourceName: "my-bucket", + resourceType: "bucket", + resourceGroup: "default", + resourceUid: "arn:aws:s3:::my-bucket", + service: "s3", + region: "us-east-1", + severity: "critical", + status: "FAIL", + delta: "new", + isMuted: false, + firstSeenAt: null, + lastSeenAt: "2024-01-01T00:00:00Z", + ...overrides, + }; +} + +describe("column-finding-resources", () => { + it("should pass delta to NotificationIndicator for resource rows", () => { + const columns = getColumnFindingResources({ + rowSelection: {}, + selectableRowCount: 1, + }); + + const selectColumn = columns.find( + (col) => (col as { id?: string }).id === "select", + ); + if (!selectColumn?.cell) { + throw new Error("select column not found"); + } + + const CellComponent = selectColumn.cell as (props: { + row: { + id: string; + original: FindingResourceRow; + toggleSelected: (selected: boolean) => void; + }; + }) => ReactNode; + + render( +
+ {CellComponent({ + row: { + id: "0", + original: makeResource(), + toggleSelected: vi.fn(), + }, + })} +
, + ); + + expect(screen.getByLabelText("Select resource")).toBeInTheDocument(); + expect(notificationIndicatorMock).toHaveBeenCalledWith( + expect.objectContaining({ + delta: "new", + isMuted: false, + }), + ); + }); + + it("should render the resource EntityInfo with resourceName as alias", () => { + const columns = getColumnFindingResources({ + rowSelection: {}, + selectableRowCount: 1, + }); + + const resourceColumn = columns.find( + (col) => (col as { id?: string }).id === "resource", + ); + if (!resourceColumn?.cell) { + throw new Error("resource column not found"); + } + + const CellComponent = resourceColumn.cell as (props: { + row: { original: FindingResourceRow }; + }) => ReactNode; + + render( +
+ {CellComponent({ + row: { + original: makeResource(), + }, + })} +
, + ); + + expect(screen.getByText("my-bucket")).toBeInTheDocument(); + expect(screen.getByText("arn:aws:s3:::my-bucket")).toBeInTheDocument(); + }); +}); diff --git a/ui/components/findings/table/column-finding-resources.tsx b/ui/components/findings/table/column-finding-resources.tsx index 98541a8316..50fbb52f20 100644 --- a/ui/components/findings/table/column-finding-resources.tsx +++ b/ui/components/findings/table/column-finding-resources.tsx @@ -25,11 +25,16 @@ import { import { getFailingForLabel } from "@/lib/date-utils"; import { FindingResourceRow } from "@/types"; +import { canMuteFindingResource } from "./finding-resource-selection"; import { FindingsSelectionContext } from "./findings-selection-context"; -import { NotificationIndicator } from "./notification-indicator"; +import { + type DeltaType, + NotificationIndicator, +} from "./notification-indicator"; const ResourceRowActions = ({ row }: { row: Row }) => { const resource = row.original; + const canMute = canMuteFindingResource(resource); const [isMuteModalOpen, setIsMuteModalOpen] = useState(false); const [isJiraModalOpen, setIsJiraModalOpen] = useState(false); const [resolvedIds, setResolvedIds] = useState([]); @@ -81,7 +86,7 @@ const ResourceRowActions = ({ row }: { row: Row }) => { return ( <> - {!resource.isMuted && ( + {canMute && ( }) => { ) } label={isResolving ? "Resolving..." : getMuteLabel()} - disabled={resource.isMuted || isResolving} + disabled={!canMute || isResolving} onSelect={handleMuteClick} /> (
@@ -178,7 +184,7 @@ export function getColumnFindingResources({ row.toggleSelected(checked === true)} onClick={(e) => e.stopPropagation()} aria-label="Select resource" @@ -198,7 +204,7 @@ export function getColumnFindingResources({
} - entityAlias={row.original.resourceGroup} + entityAlias={row.original.resourceName} entityId={row.original.resourceUid} />
@@ -213,8 +219,12 @@ export function getColumnFindingResources({ ), cell: ({ row }) => { const rawStatus = row.original.status; - const status = - rawStatus === "MUTED" ? "FAIL" : (rawStatus as FindingStatus); + const status: FindingStatus = + rawStatus === "MUTED" || rawStatus === "FAIL" + ? "FAIL" + : rawStatus === "PASS" + ? "PASS" + : "FAIL"; return ; }, enableSorting: false, diff --git a/ui/components/findings/table/finding-group-selection.test.ts b/ui/components/findings/table/finding-group-selection.test.ts new file mode 100644 index 0000000000..f00d17a73e --- /dev/null +++ b/ui/components/findings/table/finding-group-selection.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from "vitest"; + +import { canMuteFindingGroup } from "./finding-group-selection"; + +describe("canMuteFindingGroup", () => { + it("returns false when impacted resources is zero", () => { + expect( + canMuteFindingGroup({ + resourcesFail: 0, + resourcesTotal: 2, + mutedCount: 0, + }), + ).toBe(false); + }); + + it("returns false when all resources are already muted", () => { + expect( + canMuteFindingGroup({ + resourcesFail: 3, + resourcesTotal: 3, + mutedCount: 3, + }), + ).toBe(false); + }); + + it("returns false when all failing resources are muted even if PASS resources exist", () => { + expect( + canMuteFindingGroup({ + resourcesFail: 2, + resourcesTotal: 5, + mutedCount: 2, + }), + ).toBe(false); + }); + + it("returns true when the group still has failing resources to mute", () => { + expect( + canMuteFindingGroup({ + resourcesFail: 2, + resourcesTotal: 5, + mutedCount: 1, + }), + ).toBe(true); + }); +}); diff --git a/ui/components/findings/table/finding-group-selection.ts b/ui/components/findings/table/finding-group-selection.ts new file mode 100644 index 0000000000..f9db1cf11e --- /dev/null +++ b/ui/components/findings/table/finding-group-selection.ts @@ -0,0 +1,13 @@ +interface FindingGroupSelectionState { + resourcesFail: number; + resourcesTotal: number; + mutedCount: number; +} + +export function canMuteFindingGroup({ + resourcesFail, + mutedCount, +}: FindingGroupSelectionState): boolean { + const allMuted = mutedCount > 0 && mutedCount === resourcesFail; + return resourcesFail > 0 && !allMuted; +} diff --git a/ui/components/findings/table/finding-resource-selection.test.ts b/ui/components/findings/table/finding-resource-selection.test.ts new file mode 100644 index 0000000000..8abb3f7a8a --- /dev/null +++ b/ui/components/findings/table/finding-resource-selection.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; + +import type { FindingResourceRow } from "@/types"; + +import { canMuteFindingResource } from "./finding-resource-selection"; + +function makeResource( + overrides?: Partial, +): FindingResourceRow { + return { + id: "finding-1", + rowType: "resource", + findingId: "finding-1", + checkId: "check-1", + providerType: "aws", + providerAlias: "prod", + providerUid: "123456789012", + resourceName: "bucket-a", + resourceType: "Bucket", + resourceGroup: "bucket-a", + resourceUid: "arn:aws:s3:::bucket-a", + service: "s3", + region: "us-east-1", + severity: "high", + status: "FAIL", + isMuted: false, + firstSeenAt: null, + lastSeenAt: null, + ...overrides, + }; +} + +describe("canMuteFindingResource", () => { + it("should allow muting FAIL resources that are not muted", () => { + expect(canMuteFindingResource(makeResource())).toBe(true); + }); + + it("should disable muting for PASS resources", () => { + expect(canMuteFindingResource(makeResource({ status: "PASS" }))).toBe( + false, + ); + }); + + it("should disable muting for already muted resources", () => { + expect(canMuteFindingResource(makeResource({ isMuted: true }))).toBe(false); + }); +}); diff --git a/ui/components/findings/table/finding-resource-selection.ts b/ui/components/findings/table/finding-resource-selection.ts new file mode 100644 index 0000000000..f6bfb3312a --- /dev/null +++ b/ui/components/findings/table/finding-resource-selection.ts @@ -0,0 +1,5 @@ +import { FindingResourceRow } from "@/types"; + +export function canMuteFindingResource(resource: FindingResourceRow): boolean { + return resource.status === "FAIL" && !resource.isMuted; +} diff --git a/ui/components/findings/table/findings-group-drill-down.tsx b/ui/components/findings/table/findings-group-drill-down.tsx index 3046c09a4a..53a568e759 100644 --- a/ui/components/findings/table/findings-group-drill-down.tsx +++ b/ui/components/findings/table/findings-group-drill-down.tsx @@ -28,6 +28,7 @@ import { FindingGroupRow, FindingResourceRow } from "@/types"; import { FloatingMuteButton } from "../floating-mute-button"; import { getColumnFindingResources } from "./column-finding-resources"; +import { canMuteFindingResource } from "./finding-resource-selection"; import { FindingsSelectionContext } from "./findings-selection-context"; import { ImpactedResourcesCell } from "./impacted-resources-cell"; import { DeltaValues, NotificationIndicator } from "./notification-indicator"; @@ -82,7 +83,7 @@ export function FindingsGroupDrillDown({ setIsLoading(loading); }; - const { sentinelRef, refresh, loadMore } = useInfiniteResources({ + const { sentinelRef, refresh, loadMore, totalCount } = useInfiniteResources({ checkId: group.checkId, hasDateOrScanFilter: hasDateOrScan, filters, @@ -95,7 +96,7 @@ export function FindingsGroupDrillDown({ const drawer = useResourceDetailDrawer({ resources, checkId: group.checkId, - totalResourceCount: group.resourcesTotal, + totalResourceCount: totalCount ?? group.resourcesTotal, onRequestMoreResources: loadMore, }); @@ -108,7 +109,7 @@ export function FindingsGroupDrillDown({ const selectedFindingIds = Object.keys(rowSelection) .filter((key) => rowSelection[key]) .map((idx) => resources[parseInt(idx)]?.findingId) - .filter(Boolean); + .filter((id): id is string => id !== null && id !== undefined && id !== ""); /** Converts resource_ids (display) โ†’ resourceUids โ†’ finding UUIDs via API. */ const resolveResourceIds = async (ids: string[]) => { @@ -124,10 +125,10 @@ export function FindingsGroupDrillDown({ }); }; - const selectableRowCount = resources.filter((r) => !r.isMuted).length; + const selectableRowCount = resources.filter(canMuteFindingResource).length; const getRowCanSelect = (row: Row): boolean => { - return !row.original.isMuted; + return canMuteFindingResource(row.original); }; const clearSelection = () => { diff --git a/ui/components/findings/table/findings-group-table.tsx b/ui/components/findings/table/findings-group-table.tsx index bcbc8934b0..3d1fd24882 100644 --- a/ui/components/findings/table/findings-group-table.tsx +++ b/ui/components/findings/table/findings-group-table.tsx @@ -14,6 +14,7 @@ import { FindingGroupRow, MetaDataProps } from "@/types"; import { FloatingMuteButton } from "../floating-mute-button"; import { getColumnFindingGroups } from "./column-finding-groups"; +import { canMuteFindingGroup } from "./finding-group-selection"; import { FindingsSelectionContext } from "./findings-selection-context"; import { InlineResourceContainer, @@ -88,13 +89,21 @@ export function FindingsGroupTable({ .filter(Boolean); // Count of selectable rows (groups where not ALL findings are muted) - const selectableRowCount = safeData.filter( - (g) => !(g.mutedCount > 0 && g.mutedCount === g.resourcesTotal), + const selectableRowCount = safeData.filter((g) => + canMuteFindingGroup({ + resourcesFail: g.resourcesFail, + resourcesTotal: g.resourcesTotal, + mutedCount: g.mutedCount, + }), ).length; const getRowCanSelect = (row: Row): boolean => { const group = row.original; - return !(group.mutedCount > 0 && group.mutedCount === group.resourcesTotal); + return canMuteFindingGroup({ + resourcesFail: group.resourcesFail, + resourcesTotal: group.resourcesTotal, + mutedCount: group.mutedCount, + }); }; const clearSelection = () => { @@ -136,8 +145,8 @@ export function FindingsGroupTable({ }; const handleDrillDown = (checkId: string, group: FindingGroupRow) => { - // No impacted resources โ†’ nothing to show, skip drill-down - if (group.resourcesFail === 0) return; + // No resources in the group โ†’ nothing to show, skip drill-down + if (group.resourcesTotal === 0) return; // Toggle: same group = collapse, different = switch if (expandedCheckId === checkId) { diff --git a/ui/components/findings/table/inline-resource-container.tsx b/ui/components/findings/table/inline-resource-container.tsx index e44c3db2de..9b85b58406 100644 --- a/ui/components/findings/table/inline-resource-container.tsx +++ b/ui/components/findings/table/inline-resource-container.tsx @@ -22,6 +22,7 @@ import { hasDateOrScanFilter } from "@/lib"; import { FindingGroupRow, FindingResourceRow } from "@/types"; import { getColumnFindingResources } from "./column-finding-resources"; +import { canMuteFindingResource } from "./finding-resource-selection"; import { FindingsSelectionContext } from "./findings-selection-context"; import { ResourceDetailDrawer, @@ -180,7 +181,7 @@ export function InlineResourceContainer({ setIsLoading(loading); }; - const { sentinelRef, refresh, loadMore } = useInfiniteResources({ + const { sentinelRef, refresh, loadMore, totalCount } = useInfiniteResources({ checkId: group.checkId, hasDateOrScanFilter: hasDateOrScan, filters, @@ -194,7 +195,7 @@ export function InlineResourceContainer({ const drawer = useResourceDetailDrawer({ resources, checkId: group.checkId, - totalResourceCount: group.resourcesTotal, + totalResourceCount: totalCount ?? group.resourcesTotal, onRequestMoreResources: loadMore, }); @@ -222,10 +223,10 @@ export function InlineResourceContainer({ }); }; - const selectableRowCount = resources.filter((r) => !r.isMuted).length; + const selectableRowCount = resources.filter(canMuteFindingResource).length; const getRowCanSelect = (row: Row): boolean => { - return !row.original.isMuted; + return canMuteFindingResource(row.original); }; const clearSelection = () => { diff --git a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx index d3e588dd9e..3835242e19 100644 --- a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx +++ b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx @@ -1,6 +1,7 @@ -import { render, screen } from "@testing-library/react"; +import { render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from "react"; +import { createPortal } from "react-dom"; import { afterEach, describe, expect, it, vi } from "vitest"; // --------------------------------------------------------------------------- @@ -10,17 +11,17 @@ import { afterEach, describe, expect, it, vi } from "vitest"; const { mockGetComplianceIcon, mockGetCompliancesOverview, - mockRouterPush, + mockWindowOpen, mockSearchParamsState, } = vi.hoisted(() => ({ mockGetComplianceIcon: vi.fn((_: string) => null as string | null), mockGetCompliancesOverview: vi.fn(), - mockRouterPush: vi.fn(), + mockWindowOpen: vi.fn(), mockSearchParamsState: { value: "" }, })); vi.mock("next/navigation", () => ({ - useRouter: () => ({ push: mockRouterPush, refresh: vi.fn() }), + useRouter: () => ({ refresh: vi.fn() }), usePathname: () => "/findings", useSearchParams: () => new URLSearchParams(mockSearchParamsState.value), redirect: vi.fn(), @@ -104,10 +105,30 @@ vi.mock("@/components/shadcn/card/card", () => ({ })); vi.mock("@/components/shadcn/dropdown", () => ({ - ActionDropdown: ({ children }: { children: ReactNode }) => ( -
{children}
+ ActionDropdown: ({ + children, + ariaLabel, + }: { + children: ReactNode; + ariaLabel?: string; + }) => ( +
+ {children} +
+ ), + ActionDropdownItem: ({ + label, + disabled, + onSelect, + }: { + label: string; + disabled?: boolean; + onSelect?: () => void; + }) => ( + ), - ActionDropdownItem: () => null, })); vi.mock("@/components/shadcn/skeleton/skeleton", () => ({ @@ -125,7 +146,25 @@ vi.mock("@/components/shadcn/tooltip", () => ({ })); vi.mock("@/components/findings/mute-findings-modal", () => ({ - MuteFindingsModal: () => null, + MuteFindingsModal: ({ + isOpen, + findingIds, + onComplete, + }: { + isOpen: boolean; + findingIds: string[]; + onComplete?: () => void; + }) => + isOpen + ? globalThis.document?.body && + // Render into body to mirror the real modal portal behavior. + createPortal( + , + globalThis.document.body, + ) + : null, })); vi.mock("@/components/findings/send-to-jira-modal", () => ({ @@ -547,9 +586,14 @@ describe("ResourceDetailDrawerContent โ€” compliance icon styling", () => { }); describe("ResourceDetailDrawerContent โ€” compliance navigation", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + it("should resolve the clicked framework against the selected scan and navigate to compliance detail", async () => { // Given const user = userEvent.setup(); + vi.stubGlobal("open", mockWindowOpen); mockSearchParamsState.value = "filter[scan__in]=scan-selected&filter[region__in]=eu-west-1"; mockGetCompliancesOverview.mockResolvedValue({ @@ -595,14 +639,17 @@ describe("ResourceDetailDrawerContent โ€” compliance navigation", () => { expect(mockGetCompliancesOverview).toHaveBeenCalledWith({ scanId: "scan-selected", }); - expect(mockRouterPush).toHaveBeenCalledWith( + expect(mockWindowOpen).toHaveBeenCalledWith( "/compliance/PCI-DSS?complianceId=compliance-1&version=4.0&scanId=scan-selected&filter%5Bregion__in%5D=eu-west-1", + "_blank", + "noopener,noreferrer", ); }); it("should use the current finding scan when no scan filter is active", async () => { // Given const user = userEvent.setup(); + vi.stubGlobal("open", mockWindowOpen); mockGetCompliancesOverview.mockResolvedValue({ data: [ { @@ -662,8 +709,134 @@ describe("ResourceDetailDrawerContent โ€” compliance navigation", () => { expect(mockGetCompliancesOverview).toHaveBeenCalledWith({ scanId: "scan-from-finding", }); - expect(mockRouterPush).toHaveBeenCalledWith( + expect(mockWindowOpen).toHaveBeenCalledWith( "/compliance/PCI-DSS?complianceId=compliance-2&version=4.0&scanId=scan-from-finding&scanData=%7B%22id%22%3A%22scan-from-finding%22%2C%22providerInfo%22%3A%7B%22provider%22%3A%22aws%22%2C%22alias%22%3A%22prod%22%2C%22uid%22%3A%22123456789%22%7D%2C%22attributes%22%3A%7B%22name%22%3A%22Nightly+scan%22%2C%22completed_at%22%3A%222026-03-30T10%3A05%3A00Z%22%7D%7D", + "_blank", + "noopener,noreferrer", + ); + }); + + it("should navigate when the finding framework is a short alias of the compliance overview framework", async () => { + // Given + const user = userEvent.setup(); + vi.stubGlobal("open", mockWindowOpen); + mockGetComplianceIcon.mockImplementation((framework: string) => + framework.toLowerCase().includes("kisa") ? "/kisa.svg" : null, + ); + mockGetCompliancesOverview.mockResolvedValue({ + data: [ + { + id: "compliance-kisa", + type: "compliance-overviews", + attributes: { + framework: "KISA-ISMS-P", + version: "1.0", + requirements_passed: 5, + requirements_failed: 1, + requirements_manual: 0, + total_requirements: 6, + }, + }, + ], + }); + const findingWithScan = { + ...mockFinding, + scan: { + id: "scan-from-finding", + name: "Nightly scan", + trigger: "manual", + state: "completed", + uniqueResourceCount: 25, + progress: 100, + duration: 300, + startedAt: "2026-03-30T10:00:00Z", + completedAt: "2026-03-30T10:05:00Z", + insertedAt: "2026-03-30T09:59:00Z", + scheduledAt: null, + }, + }; + + render( + , + ); + + // When + await user.click( + screen.getByRole("button", { + name: "Open KISA compliance details", + }), + ); + + // Then + expect(mockGetCompliancesOverview).toHaveBeenCalledWith({ + scanId: "scan-from-finding", + }); + expect(mockWindowOpen).toHaveBeenCalledWith( + "/compliance/KISA-ISMS-P?complianceId=compliance-kisa&version=1.0&scanId=scan-from-finding&scanData=%7B%22id%22%3A%22scan-from-finding%22%2C%22providerInfo%22%3A%7B%22provider%22%3A%22aws%22%2C%22alias%22%3A%22prod%22%2C%22uid%22%3A%22123456789%22%7D%2C%22attributes%22%3A%7B%22name%22%3A%22Nightly+scan%22%2C%22completed_at%22%3A%222026-03-30T10%3A05%3A00Z%22%7D%7D", + "_blank", + "noopener,noreferrer", ); }); }); + +describe("ResourceDetailDrawerContent โ€” other findings mute refresh", () => { + it("should update only the muted other-finding row without refreshing the current finding group", async () => { + // Given + const user = userEvent.setup(); + const onMuteComplete = vi.fn(); + const otherFinding: ResourceDrawerFinding = { + ...mockFinding, + id: "finding-2", + uid: "uid-2", + checkId: "ec2_check", + checkTitle: "EC2 Check", + updatedAt: "2026-03-30T10:05:00Z", + }; + + render( + , + ); + + // When + const row = screen.getByText("EC2 Check").closest("tr"); + expect(row).not.toBeNull(); + + await user.click( + within(row as HTMLElement).getByRole("button", { name: "Mute" }), + ); + await user.click( + screen.getByRole("button", { name: "Confirm mute finding-2" }), + ); + + // Then + expect( + within(row as HTMLElement).getByRole("button", { name: "Muted" }), + ).toBeDisabled(); + expect(onMuteComplete).not.toHaveBeenCalled(); + }); +}); diff --git a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx index 509f128b97..09bf786f07 100644 --- a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx +++ b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx @@ -12,7 +12,7 @@ import { } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useSearchParams } from "next/navigation"; import { useState } from "react"; import { getCompliancesOverview } from "@/actions/compliances"; @@ -84,7 +84,90 @@ function normalizeComplianceFrameworkName(framework: string): string { return framework .trim() .toLowerCase() - .replace(/[\s_]+/g, "-"); + .replace(/[\s_]+/g, "-") + .replace(/-+/g, "-"); +} + +function stripComplianceVersionSuffix(framework: string): string { + return framework.replace(/-\d+(?:\.\d+)*$/g, ""); +} + +function canonicalComplianceKey(framework: string): string { + return stripComplianceVersionSuffix( + normalizeComplianceFrameworkName(framework), + ) + .replace(/[^a-z0-9]+/g, "") + .trim(); +} + +function complianceTokens(framework: string): string[] { + return stripComplianceVersionSuffix( + normalizeComplianceFrameworkName(framework), + ) + .split("-") + .map((token) => token.trim()) + .filter(Boolean) + .filter((token) => !/^\d+(?:\.\d+)*$/.test(token)); +} + +function complianceMatchScore( + sourceFramework: string, + targetFramework: string, +): number { + const normalizedSource = normalizeComplianceFrameworkName(sourceFramework); + const normalizedTarget = normalizeComplianceFrameworkName(targetFramework); + + if (normalizedSource === normalizedTarget) { + return 5; + } + + const canonicalSource = canonicalComplianceKey(sourceFramework); + const canonicalTarget = canonicalComplianceKey(targetFramework); + + if (canonicalSource === canonicalTarget) { + return 4; + } + + if (canonicalSource && canonicalTarget) { + const sourceTokens = canonicalSource.split("-"); + const targetTokens = canonicalTarget.split("-"); + if ( + sourceTokens.length !== targetTokens.length && + (sourceTokens.every((t) => targetTokens.includes(t)) || + targetTokens.every((t) => sourceTokens.includes(t))) + ) { + return 3; + } + } + + const sourceTokens = complianceTokens(sourceFramework); + const targetTokens = complianceTokens(targetFramework); + if (!sourceTokens.length || !targetTokens.length) { + return 0; + } + + const sourceMatchesTarget = sourceTokens.every((token) => + targetTokens.includes(token), + ); + const targetMatchesSource = targetTokens.every((token) => + sourceTokens.includes(token), + ); + + if (sourceMatchesTarget || targetMatchesSource) { + return 2; + } + + if ( + sourceTokens.some((token) => targetTokens.includes(token)) && + canonicalSource && + canonicalTarget && + (canonicalTarget.includes(canonicalSource) || + canonicalSource.includes(canonicalTarget)) + ) { + return 1; + } + + return 0; } function parseSelectedScanIds(scanFilterValue: string | null): string[] { @@ -110,12 +193,13 @@ function resolveComplianceMatch( return null; } - const normalizedFramework = normalizeComplianceFrameworkName(framework); - const match = compliances.find( - (compliance) => - normalizeComplianceFrameworkName(compliance.attributes.framework) === - normalizedFramework, - ); + const match = compliances + .map((compliance) => ({ + compliance, + score: complianceMatchScore(framework, compliance.attributes.framework), + })) + .filter(({ score }) => score > 0) + .sort((a, b) => b.score - a.score)[0]?.compliance; if (!match) { return null; @@ -202,13 +286,15 @@ export function ResourceDetailDrawerContent({ onNavigateNext, onMuteComplete, }: ResourceDetailDrawerContentProps) { - const router = useRouter(); const searchParams = useSearchParams(); const [isMuteModalOpen, setIsMuteModalOpen] = useState(false); const [isJiraModalOpen, setIsJiraModalOpen] = useState(false); const [resolvingFramework, setResolvingFramework] = useState( null, ); + const [optimisticallyMutedIds, setOptimisticallyMutedIds] = useState< + Set + >(new Set()); // Initial load โ€” no check metadata yet if (!checkMeta && isLoading) { @@ -284,7 +370,7 @@ export function ResourceDetailDrawerContent({ return; } - router.push( + window.open( buildComplianceDetailHref({ complianceId: complianceMatch.complianceId, framework: complianceMatch.framework, @@ -294,6 +380,8 @@ export function ResourceDetailDrawerContent({ currentFinding: f, includeScanData: f?.scan?.id === complianceScanId, }), + "_blank", + "noopener,noreferrer", ); } catch (error) { console.error("Error resolving compliance detail:", error); @@ -428,10 +516,10 @@ export function ResourceDetailDrawerContent({ )}
- {/* Navigation: "Impacted Resource (X of N)" */} + {/* Navigation: "Resource (X of N)" */}
- Impacted Resource + Resource {currentIndex + 1} of {totalResources} @@ -477,7 +565,7 @@ export function ResourceDetailDrawerContent({ /> } - entityAlias={f.resourceGroup} + entityAlias={f.resourceName} entityId={f.resourceUid} idLabel="UID" /> @@ -505,7 +593,9 @@ export function ResourceDetailDrawerContent({ {getFailingForLabel(f.firstSeenAt) || "-"} -
+ + {f.resourceGroup || "-"} + {/* Row 3: IDs */} @@ -529,6 +619,11 @@ export function ResourceDetailDrawerContent({ className="max-w-full text-sm" /> + + {/* Row 4: Resource metadata */} + + {f.resourceType || "-"} +
{/* Actions button โ€” fixed size, aligned with row 1 */} @@ -757,10 +852,7 @@ export function ResourceDetailDrawerContent({
) : ( <> -
-

- Failed Findings For This Resource -

+
{otherFindings.length} Total Entries @@ -796,7 +888,18 @@ export function ResourceDetailDrawerContent({ {otherFindings.length > 0 ? ( otherFindings.map((finding) => ( - + + setOptimisticallyMutedIds((prev) => + new Set(prev).add(finding.id), + ) + } + /> )) ) : ( @@ -908,19 +1011,32 @@ export function ResourceDetailDrawerContent({ ); } -function OtherFindingRow({ finding }: { finding: ResourceDrawerFinding }) { +function OtherFindingRow({ + finding, + isOptimisticallyMuted, + onMuted, +}: { + finding: ResourceDrawerFinding; + isOptimisticallyMuted: boolean; + onMuted: () => void; +}) { const [isMuteModalOpen, setIsMuteModalOpen] = useState(false); const [isJiraModalOpen, setIsJiraModalOpen] = useState(false); + const isMuted = finding.isMuted || isOptimisticallyMuted; const findingUrl = `/findings?filter%5Bcheck_id__in%5D=${encodeURIComponent(finding.checkId)}&filter%5Bmuted%5D=include`; return ( <> - {!finding.isMuted && ( + {!isMuted && ( { + setIsMuteModalOpen(false); + onMuted(); + }} /> )} window.open(findingUrl, "_blank", "noopener,noreferrer")} > - + @@ -955,14 +1071,14 @@ function OtherFindingRow({ finding }: { finding: ResourceDrawerFinding }) { ) : ( ) } - label={finding.isMuted ? "Muted" : "Mute"} - disabled={finding.isMuted} + label={isMuted ? "Muted" : "Mute"} + disabled={isMuted} onSelect={() => setIsMuteModalOpen(true)} /> ({ + Skeleton: ({ className }: { className?: string }) => ( +
+ ), +})); + +import { ResourceDetailSkeleton } from "./resource-detail-skeleton"; + +describe("ResourceDetailSkeleton", () => { + it("should include placeholders for group and resource type fields", () => { + render(); + + const blocks = screen.getAllByTestId("skeleton-block"); + const classes = blocks.map( + (block) => block.getAttribute("data-class") ?? "", + ); + + expect(classes).toContain("h-3.5 w-10 rounded"); + expect(classes).toContain("h-5 w-18 rounded"); + expect(classes).toContain("h-3.5 w-20 rounded"); + expect(classes).toContain("h-5 w-28 rounded"); + }); +}); diff --git a/ui/components/findings/table/resource-detail-drawer/resource-detail-skeleton.tsx b/ui/components/findings/table/resource-detail-drawer/resource-detail-skeleton.tsx index ed123983f5..9ef08ee14e 100644 --- a/ui/components/findings/table/resource-detail-drawer/resource-detail-skeleton.tsx +++ b/ui/components/findings/table/resource-detail-drawer/resource-detail-skeleton.tsx @@ -2,8 +2,8 @@ import { Skeleton } from "@/components/shadcn/skeleton/skeleton"; /** * Skeleton placeholder for the resource info grid in the detail drawer. - * Mirrors the 4-column layout: EntityInfo ร— 2, InfoField ร— 2 per row, - * plus the actions button. + * Mirrors the drawer layout so added metadata fields don't leave visual gaps + * while the next resource is loading. */ export function ResourceDetailSkeleton() { return ( @@ -15,16 +15,19 @@ export function ResourceDetailSkeleton() { - {/* Row 2: Last detected, First seen, Failing for */} + {/* Row 2: Last detected, First seen, Failing for, Group */} -
+ {/* Row 3: Check ID, Finding ID, Finding UID */} + + {/* Row 4: Resource type */} +
{/* Actions button */} diff --git a/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.test.ts b/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.test.ts index 404be9b165..4ce921a4e8 100644 --- a/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.test.ts +++ b/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.test.ts @@ -26,6 +26,7 @@ vi.mock("next/navigation", () => ({ // Import after mocks // --------------------------------------------------------------------------- +import type { ResourceDrawerFinding } from "@/actions/findings"; import type { FindingResourceRow } from "@/types"; import { useResourceDetailDrawer } from "./use-resource-detail-drawer"; @@ -60,6 +61,46 @@ function makeResource( } as FindingResourceRow; } +function makeDrawerFinding( + overrides?: Partial, +): ResourceDrawerFinding { + return { + id: "finding-1", + uid: "uid-1", + checkId: "s3_check", + checkTitle: "S3 Check", + status: "FAIL", + severity: "high", + delta: null, + isMuted: false, + mutedReason: null, + firstSeenAt: null, + updatedAt: null, + resourceId: "resource-1", + resourceUid: "arn:aws:s3:::my-bucket", + resourceName: "my-bucket", + resourceService: "s3", + resourceRegion: "us-east-1", + resourceType: "bucket", + resourceGroup: "default", + providerType: "aws", + providerAlias: "prod", + providerUid: "123", + risk: "high", + description: "desc", + statusExtended: "status", + complianceFrameworks: [], + categories: [], + remediation: { + recommendation: { text: "", url: "" }, + code: { cli: "", other: "", nativeiac: "", terraform: "" }, + }, + additionalUrls: [], + scan: null, + ...overrides, + }; +} + // --------------------------------------------------------------------------- // Fix 2: AbortController cleanup on unmount // --------------------------------------------------------------------------- @@ -128,3 +169,212 @@ describe("useResourceDetailDrawer โ€” unmount cleanup", () => { expect(abortSpy).not.toHaveBeenCalled(); }); }); + +describe("useResourceDetailDrawer โ€” other findings filtering", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should exclude the current finding from otherFindings and preserve API order", async () => { + const resources = [makeResource()]; + + getLatestFindingsByResourceUidMock.mockResolvedValue({ data: [] }); + adaptFindingsByResourceResponseMock.mockReturnValue([ + makeDrawerFinding({ + id: "current", + checkId: "s3_check", + checkTitle: "Current", + status: "FAIL", + severity: "critical", + }), + makeDrawerFinding({ + id: "other-1", + checkId: "check-other-1", + checkTitle: "Other 1", + status: "PASS", + severity: "critical", + }), + makeDrawerFinding({ + id: "other-2", + checkId: "check-other-2", + checkTitle: "Other 2", + status: "FAIL", + severity: "medium", + }), + ]); + + const { result } = renderHook(() => + useResourceDetailDrawer({ + resources, + checkId: "s3_check", + }), + ); + + await act(async () => { + result.current.openDrawer(0); + await Promise.resolve(); + }); + + expect(result.current.otherFindings.map((finding) => finding.id)).toEqual([ + "other-1", + "other-2", + ]); + }); + + it("should keep isNavigating true for a cached resource long enough to render skeletons", async () => { + vi.useFakeTimers(); + + const resources = [ + makeResource({ + id: "row-1", + findingId: "finding-1", + resourceUid: "arn:aws:s3:::first-bucket", + resourceName: "first-bucket", + }), + makeResource({ + id: "row-2", + findingId: "finding-2", + resourceUid: "arn:aws:s3:::second-bucket", + resourceName: "second-bucket", + }), + ]; + + getLatestFindingsByResourceUidMock.mockImplementation( + async ({ resourceUid }: { resourceUid: string }) => ({ + data: [resourceUid], + }), + ); + adaptFindingsByResourceResponseMock.mockImplementation( + (response: { data: string[] }) => [ + makeDrawerFinding({ + id: response.data[0].includes("first") ? "finding-1" : "finding-2", + resourceUid: response.data[0], + resourceName: response.data[0].includes("first") + ? "first-bucket" + : "second-bucket", + }), + ], + ); + + const { result } = renderHook(() => + useResourceDetailDrawer({ + resources, + checkId: "s3_check", + }), + ); + + await act(async () => { + result.current.openDrawer(0); + await Promise.resolve(); + }); + + await act(async () => { + result.current.navigateNext(); + await Promise.resolve(); + }); + + expect(result.current.currentIndex).toBe(1); + expect(result.current.currentFinding?.id).toBe("finding-2"); + + act(() => { + result.current.navigatePrev(); + }); + + expect(result.current.currentIndex).toBe(0); + expect(result.current.isNavigating).toBe(true); + + await act(async () => { + vi.runAllTimers(); + await Promise.resolve(); + }); + + expect(result.current.isNavigating).toBe(false); + expect(result.current.currentFinding?.id).toBe("finding-1"); + + vi.useRealTimers(); + }); + + it("should keep isNavigating true for a fast uncached navigation long enough to avoid flicker", async () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-04-08T15:00:00.000Z")); + + const resources = [ + makeResource({ + id: "row-1", + findingId: "finding-1", + resourceUid: "arn:aws:s3:::first-bucket", + resourceName: "first-bucket", + }), + makeResource({ + id: "row-2", + findingId: "finding-2", + resourceUid: "arn:aws:s3:::second-bucket", + resourceName: "second-bucket", + }), + ]; + + getLatestFindingsByResourceUidMock.mockImplementation( + async ({ resourceUid }: { resourceUid: string }) => ({ + data: [resourceUid], + }), + ); + adaptFindingsByResourceResponseMock.mockImplementation( + (response: { data: string[] }) => [ + makeDrawerFinding({ + id: response.data[0].includes("first") ? "finding-1" : "finding-2", + resourceUid: response.data[0], + resourceName: response.data[0].includes("first") + ? "first-bucket" + : "second-bucket", + }), + ], + ); + + const { result } = renderHook(() => + useResourceDetailDrawer({ + resources, + checkId: "s3_check", + }), + ); + + await act(async () => { + result.current.openDrawer(0); + await Promise.resolve(); + }); + + act(() => { + result.current.navigateNext(); + }); + + expect(result.current.currentIndex).toBe(1); + expect(result.current.isNavigating).toBe(true); + + await act(async () => { + await Promise.resolve(); + }); + + expect(result.current.currentFinding?.id).toBe("finding-2"); + expect(result.current.isNavigating).toBe(true); + + await act(async () => { + vi.advanceTimersByTime(119); + await Promise.resolve(); + }); + + expect(result.current.isNavigating).toBe(true); + + await act(async () => { + vi.advanceTimersByTime(1); + await Promise.resolve(); + }); + + await act(async () => { + vi.runOnlyPendingTimers(); + await Promise.resolve(); + }); + + expect(result.current.isNavigating).toBe(false); + + vi.useRealTimers(); + }); +}); diff --git a/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.ts b/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.ts index d1d9eb96d3..c9bf263dc0 100644 --- a/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.ts +++ b/ui/components/findings/table/resource-detail-drawer/use-resource-detail-drawer.ts @@ -9,6 +9,10 @@ import { } from "@/actions/findings"; import { FindingResourceRow } from "@/types"; +// Keep fast carousel navigations in a loading state for one short beat so +// React doesn't batch away the skeleton frame when switching resources. +const MIN_NAVIGATION_SKELETON_MS = 300; + /** * Check-level metadata that is identical across all resources for a given check. * Extracted once on first successful fetch and kept stable during navigation. @@ -83,18 +87,65 @@ export function useResourceDetailDrawer({ const cacheRef = useRef>(new Map()); const checkMetaRef = useRef(null); const fetchControllerRef = useRef(null); + const navigationTimeoutRef = useRef | null>( + null, + ); + const navigationStartedAtRef = useRef(null); + + const clearNavigationTimeout = () => { + if (navigationTimeoutRef.current !== null) { + clearTimeout(navigationTimeoutRef.current); + navigationTimeoutRef.current = null; + } + }; + + const finishNavigation = () => { + clearNavigationTimeout(); + setIsLoading(false); + + const navigationStartedAt = navigationStartedAtRef.current; + if (navigationStartedAt === null) { + navigationStartedAtRef.current = null; + setIsNavigating(false); + return; + } + + const elapsed = Date.now() - navigationStartedAt; + const remaining = Math.max(0, MIN_NAVIGATION_SKELETON_MS - elapsed); + + if (remaining === 0) { + navigationStartedAtRef.current = null; + setIsNavigating(false); + return; + } + + navigationTimeoutRef.current = setTimeout(() => { + setIsNavigating(false); + navigationStartedAtRef.current = null; + navigationTimeoutRef.current = null; + }, remaining); + }; + + const startNavigation = () => { + clearNavigationTimeout(); + navigationStartedAtRef.current = Date.now(); + setIsNavigating(true); + }; // Abort any in-flight request on unmount to prevent state updates // on an already-unmounted component. useEffect(() => { return () => { fetchControllerRef.current?.abort(); + clearNavigationTimeout(); + navigationStartedAtRef.current = null; }; }, []); const fetchFindings = async (resourceUid: string) => { // Abort any in-flight request to prevent stale data from out-of-order responses fetchControllerRef.current?.abort(); + clearNavigationTimeout(); const controller = new AbortController(); fetchControllerRef.current = controller; @@ -106,8 +157,7 @@ export function useResourceDetailDrawer({ if (main) checkMetaRef.current = extractCheckMeta(main); } setFindings(cached); - setIsLoading(false); - setIsNavigating(false); + finishNavigation(); return; } @@ -135,8 +185,7 @@ export function useResourceDetailDrawer({ } } finally { if (!controller.signal.aborted) { - setIsLoading(false); - setIsNavigating(false); + finishNavigation(); } } }; @@ -145,8 +194,11 @@ export function useResourceDetailDrawer({ const resource = resources[index]; if (!resource) return; + clearNavigationTimeout(); + navigationStartedAtRef.current = null; setCurrentIndex(index); setIsOpen(true); + setIsNavigating(false); setFindings([]); fetchFindings(resource.resourceUid); }; @@ -159,7 +211,7 @@ export function useResourceDetailDrawer({ const resource = resources[currentIndex]; if (!resource) return; cacheRef.current.delete(resource.resourceUid); - setIsNavigating(true); + startNavigation(); fetchFindings(resource.resourceUid); }; @@ -168,7 +220,7 @@ export function useResourceDetailDrawer({ if (!resource) return; setCurrentIndex(index); - setIsNavigating(true); + startNavigation(); fetchFindings(resource.resourceUid); }; diff --git a/ui/components/scans/scans-filters.tsx b/ui/components/scans/scans-filters.tsx index 6273acac77..60dbca0bfc 100644 --- a/ui/components/scans/scans-filters.tsx +++ b/ui/components/scans/scans-filters.tsx @@ -3,20 +3,23 @@ import { X } from "lucide-react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { ScanSelector } from "@/components/compliance/compliance-header"; import { filterScans } from "@/components/filters/data-filters"; import { FilterControls } from "@/components/filters/filter-controls"; import { Badge } from "@/components/shadcn/badge/badge"; import { useRelatedFilters } from "@/hooks"; -import { FilterEntity, FilterType } from "@/types"; +import { ExpandedScanData, FilterEntity, FilterType } from "@/types"; interface ScansFiltersProps { providerUIDs: string[]; providerDetails: { [uid: string]: FilterEntity }[]; + completedScans?: ExpandedScanData[]; } export const ScansFilters = ({ providerUIDs, providerDetails, + completedScans = [], }: ScansFiltersProps) => { const router = useRouter(); const pathname = usePathname(); @@ -36,24 +39,50 @@ export const ScansFilters = ({ router.push(`${pathname}?${params.toString()}`); }; - const scanIdChip = idFilter ? ( -
- - Scan: - {idFilter} + const handleScanChange = (selectedScanId: string) => { + const params = new URLSearchParams(searchParams.toString()); + params.set("filter[id__in]", selectedScanId); + router.push(`${pathname}?${params.toString()}`); + }; + + const scanIdElement = idFilter ? ( + completedScans.length > 0 ? ( +
+ - -
+
+ ) : ( +
+ + + Scan: + + {idFilter} + + +
+ ) ) : null; return ( @@ -68,7 +97,7 @@ export const ScansFilters = ({ index: 1, }, ]} - prependElement={scanIdChip} + prependElement={scanIdElement} /> ); }; diff --git a/ui/components/shadcn/card/card.tsx b/ui/components/shadcn/card/card.tsx index 8226ae698f..7c60a51f5f 100644 --- a/ui/components/shadcn/card/card.tsx +++ b/ui/components/shadcn/card/card.tsx @@ -20,7 +20,7 @@ const cardVariants = cva("flex flex-col gap-6 rounded-xl border", { inner: "rounded-[12px] backdrop-blur-[46px] border-border-neutral-tertiary bg-bg-neutral-tertiary", danger: - "gap-1 rounded-[12px] border-border-error-primary bg-bg-fail-secondary", + "gap-1 rounded-[12px] border-[rgba(67,34,50,0.5)] bg-[rgba(67,34,50,0.2)] dark:border-[rgba(67,34,50,0.7)] dark:bg-[rgba(67,34,50,0.3)]", }, padding: { default: "", diff --git a/ui/components/ui/entities/date-with-time.tsx b/ui/components/ui/entities/date-with-time.tsx index fd43fdbd5a..90a801e9ed 100644 --- a/ui/components/ui/entities/date-with-time.tsx +++ b/ui/components/ui/entities/date-with-time.tsx @@ -1,5 +1,10 @@ import { format, parseISO } from "date-fns"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/shadcn/tooltip"; import { cn } from "@/lib/utils"; interface DateWithTimeProps { @@ -33,25 +38,52 @@ export const DateWithTime = ({ ?.substring(0, 3) .toUpperCase() || ""; - return ( + const fullText = showTime + ? `${formattedDate} ${formattedTime} ${timezone}` + : formattedDate; + + const content = (
- + {formattedDate} {showTime && ( - + {formattedTime} {timezone} )}
); + + if (inline) { + return ( + + +
{content}
+
+ {fullText} +
+ ); + } + + return content; } catch { return -; } diff --git a/ui/hooks/use-infinite-resources.test.ts b/ui/hooks/use-infinite-resources.test.ts index 49ab0f9105..618de56fba 100644 --- a/ui/hooks/use-infinite-resources.test.ts +++ b/ui/hooks/use-infinite-resources.test.ts @@ -163,6 +163,38 @@ describe("useInfiniteResources", () => { findingGroupActionsMock.getLatestFindingGroupResources, ).not.toHaveBeenCalled(); }); + + it("should forward the active finding-group filters to the resources endpoint", async () => { + // Given + const apiResponse = makeApiResponse([], { pages: 1 }); + const filters = { + "filter[status__in]": "PASS", + "filter[severity__in]": "medium", + "filter[provider_type__in]": "aws", + }; + findingGroupActionsMock.getLatestFindingGroupResources.mockResolvedValue( + apiResponse, + ); + findingGroupActionsMock.adaptFindingGroupResourcesResponse.mockReturnValue( + [], + ); + + // When + renderHook(() => useInfiniteResources(defaultOptions({ filters }))); + await flushAsync(); + + // Then + expect( + findingGroupActionsMock.getLatestFindingGroupResources, + ).toHaveBeenCalledWith( + expect.objectContaining({ + checkId: "check_1", + page: 1, + pageSize: 10, + filters, + }), + ); + }); }); describe("when all resources fit in one page", () => { diff --git a/ui/hooks/use-infinite-resources.ts b/ui/hooks/use-infinite-resources.ts index fc720dd9f7..df710ebf10 100644 --- a/ui/hooks/use-infinite-resources.ts +++ b/ui/hooks/use-infinite-resources.ts @@ -32,6 +32,8 @@ interface UseInfiniteResourcesReturn { refresh: () => void; /** Imperatively load the next page (e.g. from drawer navigation). */ loadMore: () => void; + /** Total number of resources matching current filters (from API pagination). */ + totalCount: number | null; } /** @@ -60,6 +62,7 @@ export function useInfiniteResources({ const currentCheckIdRef = useRef(checkId); const controllerRef = useRef(null); const observerRef = useRef(null); + const totalCountRef = useRef(null); // Store latest values in refs so the fetch function always reads current values // without being recreated on every render @@ -70,6 +73,7 @@ export function useInfiniteResources({ const onSetLoadingRef = useRef(onSetLoading); // Keep refs in sync with latest props + currentCheckIdRef.current = checkId; hasDateOrScanRef.current = hasDateOrScanFilter; filtersRef.current = filters; onSetResourcesRef.current = onSetResources; @@ -110,6 +114,7 @@ export function useInfiniteResources({ ); const totalPages = response?.meta?.pagination?.pages ?? 1; const hasMore = page < totalPages; + totalCountRef.current = response?.meta?.pagination?.count ?? null; // Commit the page number only after a successful (non-aborted) fetch. // This prevents a premature pageRef increment from loadNextPage being @@ -209,5 +214,10 @@ export function useInfiniteResources({ fetchPage(1, false, currentCheckIdRef.current, controller.signal); } - return { sentinelRef, refresh, loadMore: loadNextPage }; + return { + sentinelRef, + refresh, + loadMore: loadNextPage, + totalCount: totalCountRef.current, + }; } diff --git a/ui/lib/findings-scan-filters.test.ts b/ui/lib/findings-scan-filters.test.ts new file mode 100644 index 0000000000..fcf32b507d --- /dev/null +++ b/ui/lib/findings-scan-filters.test.ts @@ -0,0 +1,112 @@ +import { describe, expect, it, vi } from "vitest"; + +import { + buildFindingScanDateFilters, + resolveFindingScanDateFilters, +} from "./findings-scan-filters"; + +describe("buildFindingScanDateFilters", () => { + it("uses an exact inserted_at filter when all selected scans belong to the same day", () => { + expect( + buildFindingScanDateFilters([ + "2026-04-07T10:00:00Z", + "2026-04-07T18:30:00Z", + ]), + ).toEqual({ + "filter[inserted_at]": "2026-04-07", + }); + }); + + it("ignores whitespace-only date strings", () => { + expect(buildFindingScanDateFilters([" ", "2026-04-07T10:00:00Z"])).toEqual( + { + "filter[inserted_at]": "2026-04-07", + }, + ); + }); + + it("uses a date range when selected scans span multiple days", () => { + expect( + buildFindingScanDateFilters([ + "2026-04-03T10:00:00Z", + "2026-04-07T18:30:00Z", + "2026-04-05T12:00:00Z", + ]), + ).toEqual({ + "filter[inserted_at__gte]": "2026-04-03", + "filter[inserted_at__lte]": "2026-04-07", + }); + }); +}); + +describe("resolveFindingScanDateFilters", () => { + it("adds the required inserted_at filter for a selected scan when the URL only contains scan__in", async () => { + const result = await resolveFindingScanDateFilters({ + filters: { + "filter[muted]": "false", + "filter[scan__in]": "scan-1", + }, + scans: [ + { + id: "scan-1", + attributes: { + inserted_at: "2026-04-07T10:00:00Z", + }, + }, + ], + loadScan: vi.fn(), + }); + + expect(result).toEqual({ + "filter[muted]": "false", + "filter[scan__in]": "scan-1", + "filter[inserted_at]": "2026-04-07", + }); + }); + + it("fetches missing scan details when the selected scan is not present in the prefetched scans list", async () => { + const loadScan = vi.fn().mockResolvedValue({ + id: "scan-2", + attributes: { + inserted_at: "2026-04-05T08:00:00Z", + }, + }); + + const result = await resolveFindingScanDateFilters({ + filters: { + "filter[scan__in]": "scan-2", + }, + scans: [], + loadScan, + }); + + expect(loadScan).toHaveBeenCalledWith("scan-2"); + expect(result).toEqual({ + "filter[scan__in]": "scan-2", + "filter[inserted_at]": "2026-04-05", + }); + }); + + it("does not override an explicit inserted_at filter already chosen in the frontend", async () => { + const result = await resolveFindingScanDateFilters({ + filters: { + "filter[scan__in]": "scan-1", + "filter[inserted_at__gte]": "2026-04-01", + }, + scans: [ + { + id: "scan-1", + attributes: { + inserted_at: "2026-04-07T10:00:00Z", + }, + }, + ], + loadScan: vi.fn(), + }); + + expect(result).toEqual({ + "filter[scan__in]": "scan-1", + "filter[inserted_at__gte]": "2026-04-01", + }); + }); +}); diff --git a/ui/lib/findings-scan-filters.ts b/ui/lib/findings-scan-filters.ts new file mode 100644 index 0000000000..dfbb1bc44c --- /dev/null +++ b/ui/lib/findings-scan-filters.ts @@ -0,0 +1,99 @@ +interface ScanDateSource { + id: string; + attributes?: { + inserted_at?: string; + }; +} + +interface ResolveFindingScanDateFiltersOptions { + filters: Record; + scans: ScanDateSource[]; + loadScan: (scanId: string) => Promise; +} + +const INSERTED_AT_FILTER_KEYS = [ + "filter[inserted_at]", + "filter[inserted_at__date]", + "filter[inserted_at__gte]", + "filter[inserted_at__lte]", +] as const; + +function getScanFilterIds(filters: Record): string[] { + const scanIds = filters["filter[scan__in]"] || filters["filter[scan]"] || ""; + return Array.from(new Set(scanIds.split(",").filter(Boolean))); +} + +function formatScanDate(dateTime?: string): string | null { + if (!dateTime) return null; + const [date] = dateTime.split("T"); + return date?.trim() || null; +} + +function hasInsertedAtFilter(filters: Record): boolean { + return INSERTED_AT_FILTER_KEYS.some((key) => Boolean(filters[key])); +} + +export function buildFindingScanDateFilters( + scanInsertedAtValues: string[], +): Record { + const dates = Array.from( + new Set(scanInsertedAtValues.map(formatScanDate).filter(Boolean)), + ).sort() as string[]; + + if (dates.length === 0) { + return {}; + } + + if (dates.length === 1) { + return { + "filter[inserted_at]": dates[0], + }; + } + + return { + "filter[inserted_at__gte]": dates[0], + "filter[inserted_at__lte]": dates[dates.length - 1], + }; +} + +export async function resolveFindingScanDateFilters({ + filters, + scans, + loadScan, +}: ResolveFindingScanDateFiltersOptions): Promise> { + const scanIds = getScanFilterIds(filters); + + if (scanIds.length === 0 || hasInsertedAtFilter(filters)) { + return filters; + } + + const scansById = new Map(scans.map((scan) => [scan.id, scan])); + const missingScanIds = scanIds.filter((scanId) => !scansById.has(scanId)); + + if (missingScanIds.length > 0) { + const missingScans = await Promise.all( + missingScanIds.map((scanId) => loadScan(scanId)), + ); + + missingScans.forEach((scan) => { + if (scan) { + scansById.set(scan.id, scan); + } + }); + } + + const scanInsertedAtValues = scanIds + .map((scanId) => scansById.get(scanId)?.attributes?.inserted_at) + .filter((insertedAt): insertedAt is string => Boolean(insertedAt)); + + const dateFilters = buildFindingScanDateFilters(scanInsertedAtValues); + + if (Object.keys(dateFilters).length === 0) { + return filters; + } + + return { + ...filters, + ...dateFilters, + }; +} diff --git a/ui/types/findings-table.ts b/ui/types/findings-table.ts index 30198404f5..f8837884f0 100644 --- a/ui/types/findings-table.ts +++ b/ui/types/findings-table.ts @@ -34,12 +34,14 @@ export interface FindingResourceRow { providerAlias: string; providerUid: string; resourceName: string; + resourceType: string; resourceGroup: string; resourceUid: string; service: string; region: string; severity: Severity; status: string; + delta?: string | null; isMuted: boolean; mutedReason?: string; firstSeenAt: string | null; From baf1194824b9f3bde6bf4594d1556d798d990f39 Mon Sep 17 00:00:00 2001 From: Davidm4r Date: Thu, 9 Apr 2026 10:11:52 +0200 Subject: [PATCH 12/36] feat(ui): invitation flow smart routing (#10589) Co-authored-by: Pablo Fernandez Guerra (PFE) <148432447+pfe-nazaries@users.noreply.github.com> Co-authored-by: Pablo F.G Co-authored-by: Claude Opus 4.6 (1M context) --- ui/CHANGELOG.md | 4 + ui/actions/invitations/invitation.ts | 35 +++ ui/app/(auth)/(guest-only)/layout.tsx | 18 ++ .../{ => (guest-only)}/sign-in/page.tsx | 0 .../{ => (guest-only)}/sign-up/page.tsx | 0 .../accept/accept-invitation-client.tsx | 219 ++++++++++++++++++ ui/app/(auth)/invitation/accept/page.tsx | 22 ++ ui/app/(auth)/layout.tsx | 20 +- ui/auth.config.ts | 11 +- .../invitations/invitation-details.tsx | 2 +- ui/lib/invitation-routing.ts | 10 + ui/proxy.ts | 22 +- ui/tests/auth/auth-middleware.spec.ts | 4 +- ui/tests/auth/auth-session-errors.spec.ts | 15 ++ 14 files changed, 360 insertions(+), 22 deletions(-) create mode 100644 ui/app/(auth)/(guest-only)/layout.tsx rename ui/app/(auth)/{ => (guest-only)}/sign-in/page.tsx (100%) rename ui/app/(auth)/{ => (guest-only)}/sign-up/page.tsx (100%) create mode 100644 ui/app/(auth)/invitation/accept/accept-invitation-client.tsx create mode 100644 ui/app/(auth)/invitation/accept/page.tsx create mode 100644 ui/lib/invitation-routing.ts diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 941e7c5ff4..c115911475 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to the **Prowler UI** are documented in this file. ### ๐Ÿš€ Added +- Invitation accept smart router for handling invitation flow routing [(#10573)](https://github.com/prowler-cloud/prowler/pull/10573) +- Invitation link backward compatibility [(#10583)](https://github.com/prowler-cloud/prowler/pull/10583) +- Updated invitation link to use smart router [(#10575)](https://github.com/prowler-cloud/prowler/pull/10575) - Multi-tenant organization management: create, switch, edit, and delete organizations from the profile page [(#10491)](https://github.com/prowler-cloud/prowler/pull/10491) - Findings grouped view with drill-down table showing resources per check, resource detail drawer, infinite scroll pagination, and bulk mute support [(#10425)](https://github.com/prowler-cloud/prowler/pull/10425) - Resource events tool to Lighthouse AI [(#10412)](https://github.com/prowler-cloud/prowler/pull/10412) @@ -18,6 +21,7 @@ All notable changes to the **Prowler UI** are documented in this file. ### ๐Ÿž Fixed +- Preserve query parameters in callbackUrl during invitation flow [(#10571)](https://github.com/prowler-cloud/prowler/pull/10571) - Deleting the active organization now switches to the target org before deleting, preventing JWT rejection from the backend [(#10491)](https://github.com/prowler-cloud/prowler/pull/10491) - Clear Filters now resets all filters including muted findings and auto-applies, Clear all in pills only removes pill-visible sub-filters, and the discard icon is now an Undo text button [(#10446)](https://github.com/prowler-cloud/prowler/pull/10446) - Send to Jira modal now dynamically fetches and displays available issue types per project instead of hardcoding `"Task"`, fixing failures on non-English Jira instances [(#10534)](https://github.com/prowler-cloud/prowler/pull/10534) diff --git a/ui/actions/invitations/invitation.ts b/ui/actions/invitations/invitation.ts index 8ad037cbbe..72f591705a 100644 --- a/ui/actions/invitations/invitation.ts +++ b/ui/actions/invitations/invitation.ts @@ -2,10 +2,13 @@ import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; +import { z } from "zod"; import { apiBaseUrl, getAuthHeaders } from "@/lib"; import { handleApiError, handleApiResponse } from "@/lib/server-actions-helper"; +const invitationTokenSchema = z.string().min(1).max(500); + export const getInvitations = async ({ page = 1, query = "", @@ -195,3 +198,35 @@ export const revokeInvite = async (formData: FormData) => { handleApiError(error); } }; + +export const acceptInvitation = async (token: string) => { + const parsed = invitationTokenSchema.safeParse(token); + if (!parsed.success) { + return { error: "Invalid invitation token" }; + } + + const headers = await getAuthHeaders({ contentType: true }); + + const url = new URL(`${apiBaseUrl}/invitations/accept`); + + const body = JSON.stringify({ + data: { + type: "invitations", + attributes: { + invitation_token: parsed.data, + }, + }, + }); + + try { + const response = await fetch(url.toString(), { + method: "POST", + headers, + body, + }); + + return handleApiResponse(response); + } catch (error) { + return handleApiError(error); + } +}; diff --git a/ui/app/(auth)/(guest-only)/layout.tsx b/ui/app/(auth)/(guest-only)/layout.tsx new file mode 100644 index 0000000000..3ff93d836b --- /dev/null +++ b/ui/app/(auth)/(guest-only)/layout.tsx @@ -0,0 +1,18 @@ +import { redirect } from "next/navigation"; +import { ReactNode } from "react"; + +import { auth } from "@/auth.config"; + +export default async function GuestOnlyLayout({ + children, +}: { + children: ReactNode; +}) { + const session = await auth(); + + if (session?.user) { + redirect("/"); + } + + return <>{children}; +} diff --git a/ui/app/(auth)/sign-in/page.tsx b/ui/app/(auth)/(guest-only)/sign-in/page.tsx similarity index 100% rename from ui/app/(auth)/sign-in/page.tsx rename to ui/app/(auth)/(guest-only)/sign-in/page.tsx diff --git a/ui/app/(auth)/sign-up/page.tsx b/ui/app/(auth)/(guest-only)/sign-up/page.tsx similarity index 100% rename from ui/app/(auth)/sign-up/page.tsx rename to ui/app/(auth)/(guest-only)/sign-up/page.tsx diff --git a/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx b/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx new file mode 100644 index 0000000000..73e6dbe8fd --- /dev/null +++ b/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx @@ -0,0 +1,219 @@ +"use client"; + +import { Icon } from "@iconify/react"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { signOut } from "next-auth/react"; +import { useEffect, useRef, useState } from "react"; + +import { acceptInvitation } from "@/actions/invitations"; +import { Button } from "@/components/shadcn"; +import { + INVITATION_ACTION_PARAM, + INVITATION_SIGNUP_ACTION, +} from "@/lib/invitation-routing"; + +type AcceptState = + | { kind: "no-token" } + | { kind: "accepting" } + | { kind: "error"; message: string; canRetry: boolean; needsSignOut: boolean } + | { kind: "choose" }; + +function mapApiError(status: number | undefined): { + message: string; + canRetry: boolean; + needsSignOut: boolean; +} { + switch (status) { + case 410: + return { + message: + "This invitation has expired. Please contact your administrator for a new one.", + canRetry: false, + needsSignOut: false, + }; + case 400: + return { + message: "This invitation has already been used.", + canRetry: false, + needsSignOut: false, + }; + case 404: + return { + message: + "This invitation was sent to a different email address. Please sign in with the correct account.", + canRetry: false, + needsSignOut: true, + }; + default: + return { + message: "Something went wrong while accepting the invitation.", + canRetry: true, + needsSignOut: false, + }; + } +} + +export function AcceptInvitationClient({ + isAuthenticated, + token, +}: { + isAuthenticated: boolean; + token: string | null; +}) { + const router = useRouter(); + const [state, setState] = useState(() => { + if (!token) return { kind: "no-token" }; + if (!isAuthenticated) return { kind: "choose" }; + return { kind: "accepting" }; + }); + const hasStartedRef = useRef(false); + + async function doAccept() { + if (!token) return; + setState({ kind: "accepting" }); + + const result = await acceptInvitation(token); + + if (result?.error) { + const { message, canRetry, needsSignOut } = mapApiError(result.status); + setState({ kind: "error", message, canRetry, needsSignOut }); + } else { + router.push("/"); + } + } + + async function handleSignOutAndRedirect() { + if (!token) return; + const callbackPath = `/invitation/accept?invitation_token=${encodeURIComponent(token)}`; + await signOut({ redirect: false }); + router.push(`/sign-in?callbackUrl=${encodeURIComponent(callbackPath)}`); + } + + useEffect(() => { + if (hasStartedRef.current) return; + hasStartedRef.current = true; + + if (!token) { + setState({ kind: "no-token" }); + return; + } + + if (isAuthenticated) { + doAccept(); + } else { + setState({ kind: "choose" }); + } + }, [token, isAuthenticated]); // eslint-disable-line react-hooks/exhaustive-deps + + return ( +
+
+ {/* No token */} + {state.kind === "no-token" && ( +
+ +

Invalid Invitation Link

+

+ No invitation token was provided. Please check the link you + received. +

+ +
+ )} + + {/* Accepting */} + {state.kind === "accepting" && ( +
+ +

Accepting Invitation...

+

+ Please wait while we process your invitation. +

+
+ )} + + {/* Error */} + {state.kind === "error" && ( +
+ +

+ Could Not Accept Invitation +

+

{state.message}

+
+ {state.canRetry && } + {state.needsSignOut ? ( + + ) : ( + + )} +
+
+ )} + + {/* Choice page for unauthenticated users */} + {state.kind === "choose" && ( +
+ +
+

+ You've Been Invited +

+

+ You've been invited to join a tenant on Prowler. How would + you like to continue? +

+
+
+ + +
+
+ )} +
+
+ ); +} diff --git a/ui/app/(auth)/invitation/accept/page.tsx b/ui/app/(auth)/invitation/accept/page.tsx new file mode 100644 index 0000000000..9bfc5e0110 --- /dev/null +++ b/ui/app/(auth)/invitation/accept/page.tsx @@ -0,0 +1,22 @@ +import { auth } from "@/auth.config"; +import { SearchParamsProps } from "@/types"; + +import { AcceptInvitationClient } from "./accept-invitation-client"; + +export default async function AcceptInvitationPage({ + searchParams, +}: { + searchParams: Promise; +}) { + const session = await auth(); + const resolvedSearchParams = await searchParams; + + const token = + typeof resolvedSearchParams?.invitation_token === "string" + ? resolvedSearchParams.invitation_token + : null; + + return ( + + ); +} diff --git a/ui/app/(auth)/layout.tsx b/ui/app/(auth)/layout.tsx index ab6b1e9bfa..07fe3a60c3 100644 --- a/ui/app/(auth)/layout.tsx +++ b/ui/app/(auth)/layout.tsx @@ -2,10 +2,8 @@ import "@/styles/globals.css"; import { GoogleTagManager } from "@next/third-parties/google"; import { Metadata, Viewport } from "next"; -import { redirect } from "next/navigation"; -import { ReactNode } from "react"; +import { ReactNode, Suspense } from "react"; -import { auth } from "@/auth.config"; import { NavigationProgress, Toaster } from "@/components/ui"; import { fontSans } from "@/config/fonts"; import { siteConfig } from "@/config/site"; @@ -31,17 +29,7 @@ export const viewport: Viewport = { ], }; -export default async function RootLayout({ - children, -}: { - children: ReactNode; -}) { - const session = await auth(); - - if (session?.user) { - redirect("/"); - } - +export default function AuthLayout({ children }: { children: ReactNode }) { return ( @@ -53,7 +41,9 @@ export default async function RootLayout({ )} > - + + + {children} { ? window.location.origin : "http://localhost:3000"; - const invitationLink = `${baseUrl}/sign-up?invitation_token=${attributes.token}`; + const invitationLink = `${baseUrl}/invitation/accept?invitation_token=${attributes.token}`; return (
diff --git a/ui/lib/invitation-routing.ts b/ui/lib/invitation-routing.ts new file mode 100644 index 0000000000..85f132d922 --- /dev/null +++ b/ui/lib/invitation-routing.ts @@ -0,0 +1,10 @@ +/** + * Query param name + value used to bypass the backward-compat redirect + * in proxy.ts when the user explicitly chose "Create an account" + * from the invitation smart router. + * + * Client sends: /sign-up?invitation_token=โ€ฆ&action=signup + * Proxy skips redirect when "action" param is present. + */ +export const INVITATION_ACTION_PARAM = "action"; +export const INVITATION_SIGNUP_ACTION = "signup"; diff --git a/ui/proxy.ts b/ui/proxy.ts index 98b0725dea..553de6e9ba 100644 --- a/ui/proxy.ts +++ b/ui/proxy.ts @@ -1,10 +1,12 @@ import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/auth.config"; +import { INVITATION_ACTION_PARAM } from "@/lib/invitation-routing"; const publicRoutes = [ "/sign-in", "/sign-up", + "/invitation/accept", // In Cloud uncomment the following lines: // "/reset-password", // "/email-verification", @@ -18,6 +20,22 @@ const isPublicRoute = (pathname: string): boolean => { // NextAuth's auth() wrapper - renamed from middleware to proxy export default auth((req: NextRequest & { auth: any }) => { const { pathname } = req.nextUrl; + + // Backward compatibility: redirect old invitation links to new smart router + // Skip redirect when the user explicitly chose "Create an account" from the smart router + if ( + pathname === "/sign-up" && + req.nextUrl.searchParams.has("invitation_token") && + !req.nextUrl.searchParams.has(INVITATION_ACTION_PARAM) + ) { + const acceptUrl = new URL("/invitation/accept", req.url); + acceptUrl.searchParams.set( + "invitation_token", + req.nextUrl.searchParams.get("invitation_token")!, + ); + return NextResponse.redirect(acceptUrl); + } + const user = req.auth?.user; const sessionError = req.auth?.error; @@ -25,13 +43,13 @@ export default auth((req: NextRequest & { auth: any }) => { if (sessionError && !isPublicRoute(pathname)) { const signInUrl = new URL("/sign-in", req.url); signInUrl.searchParams.set("error", sessionError); - signInUrl.searchParams.set("callbackUrl", pathname); + signInUrl.searchParams.set("callbackUrl", pathname + req.nextUrl.search); return NextResponse.redirect(signInUrl); } if (!user && !isPublicRoute(pathname)) { const signInUrl = new URL("/sign-in", req.url); - signInUrl.searchParams.set("callbackUrl", pathname); + signInUrl.searchParams.set("callbackUrl", pathname + req.nextUrl.search); return NextResponse.redirect(signInUrl); } diff --git a/ui/tests/auth/auth-middleware.spec.ts b/ui/tests/auth/auth-middleware.spec.ts index 959f08250d..d7f1d23619 100644 --- a/ui/tests/auth/auth-middleware.spec.ts +++ b/ui/tests/auth/auth-middleware.spec.ts @@ -65,7 +65,9 @@ test.describe("Middleware Error Handling", () => { await freshPage.goto(`/scans?e2e_mw=${cacheBuster}`, { waitUntil: "commit", }); - await freshSignInPage.verifyRedirectWithCallback("/scans"); + await freshSignInPage.verifyRedirectWithCallback( + `/scans?e2e_mw=${cacheBuster}`, + ); } finally { await invalidSessionContext.close(); } diff --git a/ui/tests/auth/auth-session-errors.spec.ts b/ui/tests/auth/auth-session-errors.spec.ts index 000ade831d..ac640d53a3 100644 --- a/ui/tests/auth/auth-session-errors.spec.ts +++ b/ui/tests/auth/auth-session-errors.spec.ts @@ -69,4 +69,19 @@ test.describe("Session Error Messages", () => { await signInPage.verifyRedirectWithCallback("/providers"); }, ); + + test( + "should preserve query parameters in callbackUrl", + { tag: ["@e2e", "@auth", "@session", "@AUTH-SESSION-E2E-005"] }, + async ({ page, context }) => { + const signInPage = new SignInPage(page); + await context.clearCookies(); + + // Navigate to a protected route with query params and assert they are preserved. + await page.goto("/providers?ref=test", { + waitUntil: "commit", + }); + await signInPage.verifyRedirectWithCallback("/providers?ref=test"); + }, + ); }); From 1bfed74db58a061d0b87cc9c242636e841a61c8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:14:27 +0200 Subject: [PATCH 13/36] chore(deps): bump docker/build-push-action from 6.19.2 to 7.0.0 (#10557) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-container-build-push.yml | 2 +- .github/workflows/api-container-checks.yml | 2 +- .github/workflows/mcp-container-build-push.yml | 2 +- .github/workflows/mcp-container-checks.yml | 2 +- .github/workflows/sdk-container-build-push.yml | 2 +- .github/workflows/sdk-container-checks.yml | 2 +- .github/workflows/ui-container-build-push.yml | 2 +- .github/workflows/ui-container-checks.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml index 0cd3b82071..178509efbb 100644 --- a/.github/workflows/api-container-build-push.yml +++ b/.github/workflows/api-container-build-push.yml @@ -148,7 +148,7 @@ jobs: - name: Build and push API container for ${{ matrix.arch }} id: container-push if: github.event_name == 'push' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.WORKING_DIRECTORY }} push: true diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml index 14c163e89a..d6334fe1e0 100644 --- a/.github/workflows/api-container-checks.yml +++ b/.github/workflows/api-container-checks.yml @@ -119,7 +119,7 @@ jobs: - name: Build container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.API_WORKING_DIR }} push: false diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml index 3f59a455db..806b826a91 100644 --- a/.github/workflows/mcp-container-build-push.yml +++ b/.github/workflows/mcp-container-build-push.yml @@ -134,7 +134,7 @@ jobs: - name: Build and push MCP container for ${{ matrix.arch }} id: container-push if: github.event_name == 'push' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.WORKING_DIRECTORY }} push: true diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml index f8fbfca12f..10020ef042 100644 --- a/.github/workflows/mcp-container-checks.yml +++ b/.github/workflows/mcp-container-checks.yml @@ -109,7 +109,7 @@ jobs: - name: Build MCP container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.MCP_WORKING_DIR }} push: false diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml index 4a0563b89f..fe586a4e2b 100644 --- a/.github/workflows/sdk-container-build-push.yml +++ b/.github/workflows/sdk-container-build-push.yml @@ -217,7 +217,7 @@ jobs: - name: Build and push SDK container for ${{ matrix.arch }} id: container-push if: github.event_name == 'push' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: . file: ${{ env.DOCKERFILE_PATH }} diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml index dacf160a86..791dcc41a1 100644 --- a/.github/workflows/sdk-container-checks.yml +++ b/.github/workflows/sdk-container-checks.yml @@ -131,7 +131,7 @@ jobs: - name: Build SDK container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: . push: false diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml index c8886a5ae9..a5328c525c 100644 --- a/.github/workflows/ui-container-build-push.yml +++ b/.github/workflows/ui-container-build-push.yml @@ -138,7 +138,7 @@ jobs: - name: Build and push UI container for ${{ matrix.arch }} id: container-push if: github.event_name == 'push' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.WORKING_DIRECTORY }} build-args: | diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml index 10a910ace4..53fa600659 100644 --- a/.github/workflows/ui-container-checks.yml +++ b/.github/workflows/ui-container-checks.yml @@ -112,7 +112,7 @@ jobs: - name: Build UI container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: context: ${{ env.UI_WORKING_DIR }} target: prod From def59a8cc23905ab463cfd2cafe0cc831ce971d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:16:00 +0200 Subject: [PATCH 14/36] chore(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0 (#10556) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-container-build-push.yml | 2 +- .github/workflows/api-container-checks.yml | 2 +- .github/workflows/mcp-container-build-push.yml | 2 +- .github/workflows/mcp-container-checks.yml | 2 +- .github/workflows/sdk-container-build-push.yml | 2 +- .github/workflows/sdk-container-checks.yml | 2 +- .github/workflows/ui-container-build-push.yml | 2 +- .github/workflows/ui-container-checks.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml index 178509efbb..3f5bd96cc2 100644 --- a/.github/workflows/api-container-build-push.yml +++ b/.github/workflows/api-container-build-push.yml @@ -143,7 +143,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build and push API container for ${{ matrix.arch }} id: container-push diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml index d6334fe1e0..bf7a2e8900 100644 --- a/.github/workflows/api-container-checks.yml +++ b/.github/workflows/api-container-checks.yml @@ -115,7 +115,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml index 806b826a91..969cb8c04d 100644 --- a/.github/workflows/mcp-container-build-push.yml +++ b/.github/workflows/mcp-container-build-push.yml @@ -129,7 +129,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build and push MCP container for ${{ matrix.arch }} id: container-push diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml index 10020ef042..d88af01ef8 100644 --- a/.github/workflows/mcp-container-checks.yml +++ b/.github/workflows/mcp-container-checks.yml @@ -105,7 +105,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build MCP container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml index fe586a4e2b..f4b8629051 100644 --- a/.github/workflows/sdk-container-build-push.yml +++ b/.github/workflows/sdk-container-build-push.yml @@ -212,7 +212,7 @@ jobs: AWS_REGION: ${{ env.AWS_REGION }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build and push SDK container for ${{ matrix.arch }} id: container-push diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml index 791dcc41a1..3d78d919c0 100644 --- a/.github/workflows/sdk-container-checks.yml +++ b/.github/workflows/sdk-container-checks.yml @@ -127,7 +127,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build SDK container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml index a5328c525c..172b3944d5 100644 --- a/.github/workflows/ui-container-build-push.yml +++ b/.github/workflows/ui-container-build-push.yml @@ -133,7 +133,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build and push UI container for ${{ matrix.arch }} id: container-push diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml index 53fa600659..ddefab0370 100644 --- a/.github/workflows/ui-container-checks.yml +++ b/.github/workflows/ui-container-checks.yml @@ -108,7 +108,7 @@ jobs: - name: Set up Docker Buildx if: steps.check-changes.outputs.any_changed == 'true' - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build UI container for ${{ matrix.arch }} if: steps.check-changes.outputs.any_changed == 'true' From eda90c4673d2b36ae7ac6a00b9c0d19fc02646de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:18:16 +0200 Subject: [PATCH 15/36] chore(deps): bump actions/upload-artifact from 6.0.0 to 7.0.0 (#10555) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/issue-triage.lock.yml | 10 +++++----- .github/workflows/ui-e2e-tests-v2.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/issue-triage.lock.yml b/.github/workflows/issue-triage.lock.yml index fcc6f1e363..34f059e023 100644 --- a/.github/workflows/issue-triage.lock.yml +++ b/.github/workflows/issue-triage.lock.yml @@ -772,7 +772,7 @@ jobs: SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Safe Outputs if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: safe-output path: ${{ env.GH_AW_SAFE_OUTPUTS }} @@ -793,13 +793,13 @@ jobs: await main(); - name: Upload sanitized agent output if: always() && env.GH_AW_AGENT_OUTPUT - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent-output path: ${{ env.GH_AW_AGENT_OUTPUT }} if-no-files-found: warn - name: Upload engine output files - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent_outputs path: | @@ -839,7 +839,7 @@ jobs: - name: Upload agent artifacts if: always() continue-on-error: true - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: agent-artifacts path: | @@ -1071,7 +1071,7 @@ jobs: await main(); - name: Upload threat detection log if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: threat-detection.log path: /tmp/gh-aw/threat-detection/detection.log diff --git a/.github/workflows/ui-e2e-tests-v2.yml b/.github/workflows/ui-e2e-tests-v2.yml index 53533474fa..c739099b08 100644 --- a/.github/workflows/ui-e2e-tests-v2.yml +++ b/.github/workflows/ui-e2e-tests-v2.yml @@ -259,7 +259,7 @@ jobs: fi - name: Upload test reports - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: failure() with: name: playwright-report From f3b142c0cf6e561ea6b980ea980104a65784750e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:19:00 +0200 Subject: [PATCH 16/36] chore(deps): bump docker/login-action from 3.7.0 to 4.0.0 (#10554) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-container-build-push.yml | 4 ++-- .github/workflows/mcp-container-build-push.yml | 4 ++-- .github/workflows/sdk-container-build-push.yml | 12 ++++++------ .github/workflows/ui-container-build-push.yml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/api-container-build-push.yml b/.github/workflows/api-container-build-push.yml index 3f5bd96cc2..b045bb0322 100644 --- a/.github/workflows/api-container-build-push.yml +++ b/.github/workflows/api-container-build-push.yml @@ -137,7 +137,7 @@ jobs: sed -i "s|prowler-cloud/prowler.git@master|prowler-cloud/prowler.git@${LATEST_SHA}|" api/pyproject.toml - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -178,7 +178,7 @@ jobs: auth.docker.io:443 production.cloudflare.docker.com:443 - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/mcp-container-build-push.yml b/.github/workflows/mcp-container-build-push.yml index 969cb8c04d..27d59d7bc1 100644 --- a/.github/workflows/mcp-container-build-push.yml +++ b/.github/workflows/mcp-container-build-push.yml @@ -123,7 +123,7 @@ jobs: persist-credentials: false - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -173,7 +173,7 @@ jobs: release-assets.githubusercontent.com:443 - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/sdk-container-build-push.yml b/.github/workflows/sdk-container-build-push.yml index f4b8629051..ebe595bbbc 100644 --- a/.github/workflows/sdk-container-build-push.yml +++ b/.github/workflows/sdk-container-build-push.yml @@ -197,13 +197,13 @@ jobs: persist-credentials: false - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Public ECR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: public.ecr.aws username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }} @@ -252,13 +252,13 @@ jobs: - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Public ECR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: public.ecr.aws username: ${{ secrets.PUBLIC_ECR_AWS_ACCESS_KEY_ID }} @@ -295,7 +295,7 @@ jobs: # Push to toniblyx/prowler only for current version (latest/stable/release tags) - name: Login to DockerHub (toniblyx) if: needs.setup.outputs.latest_tag == 'latest' - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.TONIBLYX_DOCKERHUB_USERNAME }} password: ${{ secrets.TONIBLYX_DOCKERHUB_PASSWORD }} @@ -320,7 +320,7 @@ jobs: # Re-login as prowlercloud for cleanup of intermediate tags - name: Login to DockerHub (prowlercloud) if: always() - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/ui-container-build-push.yml b/.github/workflows/ui-container-build-push.yml index 172b3944d5..4b73540b9b 100644 --- a/.github/workflows/ui-container-build-push.yml +++ b/.github/workflows/ui-container-build-push.yml @@ -127,7 +127,7 @@ jobs: persist-credentials: false - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -172,7 +172,7 @@ jobs: production.cloudflare.docker.com:443 - name: Login to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From c21cf0ac20afa594872e3bf8ce36de94314a445f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:19:28 +0200 Subject: [PATCH 17/36] chore(deps): bump tj-actions/changed-files from 47.0.4 to 47.0.5 (#10552) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/api-code-quality.yml | 2 +- .github/workflows/api-container-checks.yml | 4 +-- .github/workflows/api-security.yml | 2 +- .github/workflows/api-tests.yml | 2 +- .github/workflows/mcp-container-checks.yml | 4 +-- .github/workflows/pr-check-changelog.yml | 2 +- .../workflows/pr-check-compliance-mapping.yml | 2 +- .github/workflows/pr-conflict-checker.yml | 2 +- .github/workflows/sdk-code-quality.yml | 2 +- .github/workflows/sdk-container-checks.yml | 4 +-- .github/workflows/sdk-security.yml | 2 +- .github/workflows/sdk-tests.yml | 32 +++++++++---------- .github/workflows/test-impact-analysis.yml | 2 +- .github/workflows/ui-container-checks.yml | 4 +-- .github/workflows/ui-tests.yml | 6 ++-- 15 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/api-code-quality.yml b/.github/workflows/api-code-quality.yml index 68928833a2..4e15f54dbf 100644 --- a/.github/workflows/api-code-quality.yml +++ b/.github/workflows/api-code-quality.yml @@ -50,7 +50,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | api/** diff --git a/.github/workflows/api-container-checks.yml b/.github/workflows/api-container-checks.yml index bf7a2e8900..5192d1bd07 100644 --- a/.github/workflows/api-container-checks.yml +++ b/.github/workflows/api-container-checks.yml @@ -42,7 +42,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: api/Dockerfile @@ -104,7 +104,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: api/** files_ignore: | diff --git a/.github/workflows/api-security.yml b/.github/workflows/api-security.yml index 9cd6b14623..505c24f57a 100644 --- a/.github/workflows/api-security.yml +++ b/.github/workflows/api-security.yml @@ -53,7 +53,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | api/** diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index ce00b03108..21c4f03965 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -99,7 +99,7 @@ jobs: - name: Check for API changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | api/** diff --git a/.github/workflows/mcp-container-checks.yml b/.github/workflows/mcp-container-checks.yml index d88af01ef8..665153f1f1 100644 --- a/.github/workflows/mcp-container-checks.yml +++ b/.github/workflows/mcp-container-checks.yml @@ -42,7 +42,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: mcp_server/Dockerfile @@ -96,7 +96,7 @@ jobs: - name: Check for MCP changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: mcp_server/** files_ignore: | diff --git a/.github/workflows/pr-check-changelog.yml b/.github/workflows/pr-check-changelog.yml index c729875843..c021e079cc 100644 --- a/.github/workflows/pr-check-changelog.yml +++ b/.github/workflows/pr-check-changelog.yml @@ -45,7 +45,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | api/** diff --git a/.github/workflows/pr-check-compliance-mapping.yml b/.github/workflows/pr-check-compliance-mapping.yml index dcf61602ba..939e17d0b4 100644 --- a/.github/workflows/pr-check-compliance-mapping.yml +++ b/.github/workflows/pr-check-compliance-mapping.yml @@ -43,7 +43,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | prowler/providers/**/services/**/*.metadata.json diff --git a/.github/workflows/pr-conflict-checker.yml b/.github/workflows/pr-conflict-checker.yml index 330a038fa0..e53a34ea23 100644 --- a/.github/workflows/pr-conflict-checker.yml +++ b/.github/workflows/pr-conflict-checker.yml @@ -39,7 +39,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: '**' diff --git a/.github/workflows/sdk-code-quality.yml b/.github/workflows/sdk-code-quality.yml index b854e9ddeb..08f8001120 100644 --- a/.github/workflows/sdk-code-quality.yml +++ b/.github/workflows/sdk-code-quality.yml @@ -46,7 +46,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ./** files_ignore: | diff --git a/.github/workflows/sdk-container-checks.yml b/.github/workflows/sdk-container-checks.yml index 3d78d919c0..19d11647c4 100644 --- a/.github/workflows/sdk-container-checks.yml +++ b/.github/workflows/sdk-container-checks.yml @@ -41,7 +41,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: Dockerfile @@ -102,7 +102,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ./** files_ignore: | diff --git a/.github/workflows/sdk-security.yml b/.github/workflows/sdk-security.yml index 2229568b3f..f4924ab030 100644 --- a/.github/workflows/sdk-security.yml +++ b/.github/workflows/sdk-security.yml @@ -44,7 +44,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ./** diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index b649db4f5a..7b9fc9d6ef 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -67,7 +67,7 @@ jobs: - name: Check for SDK changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ./** files_ignore: | @@ -109,7 +109,7 @@ jobs: - name: Check if AWS files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-aws - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/aws/** @@ -239,7 +239,7 @@ jobs: - name: Check if Azure files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-azure - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/azure/** @@ -263,7 +263,7 @@ jobs: - name: Check if GCP files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-gcp - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/gcp/** @@ -287,7 +287,7 @@ jobs: - name: Check if Kubernetes files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-kubernetes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/kubernetes/** @@ -311,7 +311,7 @@ jobs: - name: Check if GitHub files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-github - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/github/** @@ -335,7 +335,7 @@ jobs: - name: Check if NHN files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-nhn - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/nhn/** @@ -359,7 +359,7 @@ jobs: - name: Check if M365 files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-m365 - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/m365/** @@ -383,7 +383,7 @@ jobs: - name: Check if IaC files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-iac - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/iac/** @@ -407,7 +407,7 @@ jobs: - name: Check if MongoDB Atlas files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-mongodbatlas - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/mongodbatlas/** @@ -431,7 +431,7 @@ jobs: - name: Check if OCI files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-oraclecloud - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/oraclecloud/** @@ -455,7 +455,7 @@ jobs: - name: Check if OpenStack files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-openstack - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/openstack/** @@ -479,7 +479,7 @@ jobs: - name: Check if Google Workspace files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-googleworkspace - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/googleworkspace/** @@ -503,7 +503,7 @@ jobs: - name: Check if Vercel files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-vercel - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/**/vercel/** @@ -527,7 +527,7 @@ jobs: - name: Check if Lib files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-lib - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/lib/** @@ -551,7 +551,7 @@ jobs: - name: Check if Config files changed if: steps.check-changes.outputs.any_changed == 'true' id: changed-config - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ./prowler/config/** diff --git a/.github/workflows/test-impact-analysis.yml b/.github/workflows/test-impact-analysis.yml index f03f99d0fc..34a1536cbc 100644 --- a/.github/workflows/test-impact-analysis.yml +++ b/.github/workflows/test-impact-analysis.yml @@ -66,7 +66,7 @@ jobs: - name: Get changed files id: changed-files - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - name: Setup Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 diff --git a/.github/workflows/ui-container-checks.yml b/.github/workflows/ui-container-checks.yml index ddefab0370..56c9dd13f4 100644 --- a/.github/workflows/ui-container-checks.yml +++ b/.github/workflows/ui-container-checks.yml @@ -42,7 +42,7 @@ jobs: - name: Check if Dockerfile changed id: dockerfile-changed - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ui/Dockerfile @@ -98,7 +98,7 @@ jobs: - name: Check for UI changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: ui/** files_ignore: | diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 57cb149523..fa28e0c569 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -49,7 +49,7 @@ jobs: - name: Check for UI changes id: check-changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ui/** @@ -62,7 +62,7 @@ jobs: - name: Get changed source files for targeted tests id: changed-source if: steps.check-changes.outputs.any_changed == 'true' - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ui/**/*.ts @@ -78,7 +78,7 @@ jobs: - name: Check for critical path changes (run all tests) id: critical-changes if: steps.check-changes.outputs.any_changed == 'true' - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | ui/lib/** From 9a6a43637d4eac7d9c982ee9db8fa82ef982d0e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:19:50 +0200 Subject: [PATCH 18/36] chore(deps): bump pnpm/action-setup from 4.2.0 to 5.0.0 (#10551) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests-v2.yml | 2 +- .github/workflows/ui-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui-e2e-tests-v2.yml b/.github/workflows/ui-e2e-tests-v2.yml index c739099b08..e75b46c687 100644 --- a/.github/workflows/ui-e2e-tests-v2.yml +++ b/.github/workflows/ui-e2e-tests-v2.yml @@ -163,7 +163,7 @@ jobs: node-version: '24.13.0' - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 with: package_json_file: ui/package.json run_install: false diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index fa28e0c569..a5a609648f 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -96,7 +96,7 @@ jobs: - name: Setup pnpm if: steps.check-changes.outputs.any_changed == 'true' - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 with: package_json_file: ui/package.json run_install: false From 82d487a1e7319f88ceb03bf10e7b2782ab86f4c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:20:11 +0200 Subject: [PATCH 19/36] chore(deps): bump sorenlouv/backport-github-action from 10.2.0 to 11.0.0 (#10540) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index feb8c7c9bf..3563db7154 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -46,7 +46,7 @@ jobs: - name: Backport PR if: steps.label_check.outputs.label_check == 'success' - uses: sorenlouv/backport-github-action@516854e7c9f962b9939085c9a92ea28411d1ae90 # v10.2.0 + uses: sorenlouv/backport-github-action@9460b7102fea25466026ce806c9ebf873ac48721 # v11.0.0 with: github_token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} auto_backport_label_prefix: ${{ env.BACKPORT_LABEL_PREFIX }} From 632f2633c128a05a0ecddf53872b9e2b9cf835ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:20:34 +0200 Subject: [PATCH 20/36] chore(deps): bump zizmorcore/zizmor-action from 0.5.0 to 0.5.2 (#10550) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-zizmor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-zizmor.yml b/.github/workflows/ci-zizmor.yml index 5962b01efd..2c8d61b961 100644 --- a/.github/workflows/ci-zizmor.yml +++ b/.github/workflows/ci-zizmor.yml @@ -49,6 +49,6 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0 + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 with: token: ${{ github.token }} From d2f7169537c0fd28630edd549cbf270c0bb51dea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:22:26 +0200 Subject: [PATCH 21/36] chore(deps): bump actions/checkout from 6.0.1 to 6.0.2 (#10548) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/helm-chart-checks.yml | 2 +- .github/workflows/helm-chart-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/helm-chart-checks.yml b/.github/workflows/helm-chart-checks.yml index a0a24c2516..27b3545a1f 100644 --- a/.github/workflows/helm-chart-checks.yml +++ b/.github/workflows/helm-chart-checks.yml @@ -36,7 +36,7 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false diff --git a/.github/workflows/helm-chart-release.yml b/.github/workflows/helm-chart-release.yml index c0c5773bdb..e25e154006 100644 --- a/.github/workflows/helm-chart-release.yml +++ b/.github/workflows/helm-chart-release.yml @@ -29,7 +29,7 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From a2b083e8c850c8adf7343b8e6bd044c13db75fb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:22:58 +0200 Subject: [PATCH 22/36] chore(deps): bump actions/cache from 5.0.3 to 5.0.4 (#10546) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests-v2.yml | 4 ++-- .github/workflows/ui-tests.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ui-e2e-tests-v2.yml b/.github/workflows/ui-e2e-tests-v2.yml index e75b46c687..13ccb954eb 100644 --- a/.github/workflows/ui-e2e-tests-v2.yml +++ b/.github/workflows/ui-e2e-tests-v2.yml @@ -172,7 +172,7 @@ jobs: run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - name: Setup pnpm and Next.js cache - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: | ${{ env.STORE_PATH }} @@ -192,7 +192,7 @@ jobs: run: pnpm run build - name: Cache Playwright browsers - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 id: playwright-cache with: path: ~/.cache/ms-playwright diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index a5a609648f..87f9564e41 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -108,7 +108,7 @@ jobs: - name: Setup pnpm and Next.js cache if: steps.check-changes.outputs.any_changed == 'true' - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: | ${{ env.STORE_PATH }} From c6c000a36932e5165612a74a6b099b1221f03b6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:23:18 +0200 Subject: [PATCH 23/36] chore(deps): bump actions/setup-node from 6.2.0 to 6.3.0 (#10545) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ui-e2e-tests-v2.yml | 2 +- .github/workflows/ui-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ui-e2e-tests-v2.yml b/.github/workflows/ui-e2e-tests-v2.yml index 13ccb954eb..a83073b16d 100644 --- a/.github/workflows/ui-e2e-tests-v2.yml +++ b/.github/workflows/ui-e2e-tests-v2.yml @@ -158,7 +158,7 @@ jobs: ' - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: '24.13.0' diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 87f9564e41..631af22615 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -90,7 +90,7 @@ jobs: - name: Setup Node.js ${{ env.NODE_VERSION }} if: steps.check-changes.outputs.any_changed == 'true' - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: ${{ env.NODE_VERSION }} From c8d41745ddd74afd4b1084ac00b941e70a66590d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:23:44 +0200 Subject: [PATCH 24/36] chore(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1 (#10544) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/prepare-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index f0aee83174..c4163aa397 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -380,7 +380,7 @@ jobs: no-changelog - name: Create draft release - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: tag_name: ${{ env.PROWLER_VERSION }} name: Prowler ${{ env.PROWLER_VERSION }} From 10dd9460e9448fb4b7f050a4fdeff906728df5cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:24:42 +0200 Subject: [PATCH 25/36] chore(deps): bump azure/setup-helm from 4.3.0 to 5.0.0 (#10543) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/helm-chart-checks.yml | 2 +- .github/workflows/helm-chart-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/helm-chart-checks.yml b/.github/workflows/helm-chart-checks.yml index 27b3545a1f..3cc857abd7 100644 --- a/.github/workflows/helm-chart-checks.yml +++ b/.github/workflows/helm-chart-checks.yml @@ -41,7 +41,7 @@ jobs: persist-credentials: false - name: Set up Helm - uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 - name: Update chart dependencies run: helm dependency update ${{ env.CHART_PATH }} diff --git a/.github/workflows/helm-chart-release.yml b/.github/workflows/helm-chart-release.yml index e25e154006..e947f8af82 100644 --- a/.github/workflows/helm-chart-release.yml +++ b/.github/workflows/helm-chart-release.yml @@ -34,7 +34,7 @@ jobs: persist-credentials: false - name: Set up Helm - uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 + uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 - name: Set appVersion from release tag run: | From ad36938717395fd2ee63d4dcd401e19d2a42ffc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:25:14 +0200 Subject: [PATCH 26/36] chore(deps): bump actions/download-artifact from 6.0.0 to 8.0.1 (#10541) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/issue-triage.lock.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/issue-triage.lock.yml b/.github/workflows/issue-triage.lock.yml index 34f059e023..b694e8ecef 100644 --- a/.github/workflows/issue-triage.lock.yml +++ b/.github/workflows/issue-triage.lock.yml @@ -880,7 +880,7 @@ jobs: destination: /opt/gh-aw/actions - name: Download agent output artifact continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ @@ -992,13 +992,13 @@ jobs: destination: /opt/gh-aw/actions - name: Download agent artifacts continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: agent-artifacts path: /tmp/gh-aw/threat-detection/ - name: Download agent output artifact continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: agent-output path: /tmp/gh-aw/threat-detection/ @@ -1174,7 +1174,7 @@ jobs: destination: /opt/gh-aw/actions - name: Download agent output artifact continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ From b0d8534907b9cdb4c04cf30952a3d795a91720a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 9 Apr 2026 14:36:55 +0200 Subject: [PATCH 27/36] feat(api): add needed changes for GoogleWorkspace compliance (#10629) --- api/CHANGELOG.md | 1 + api/src/backend/tasks/jobs/export.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 936ce9f6b3..33c573924a 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to the **Prowler API** are documented in this file. - `VALKEY_SCHEME`, `VALKEY_USERNAME`, and `VALKEY_PASSWORD` environment variables to configure Celery broker TLS/auth connection details for Valkey/ElastiCache [(#10420)](https://github.com/prowler-cloud/prowler/pull/10420) - `Vercel` provider support [(#10190)](https://github.com/prowler-cloud/prowler/pull/10190) - Finding groups list and latest endpoints support `sort=delta`, ordering by `new_count` then `changed_count` so groups with the most new findings rank highest [(#10606)](https://github.com/prowler-cloud/prowler/pull/10606) +- Handle CIS and CISA SCuBA compliance framework from google workspace [(#10629)](https://github.com/prowler-cloud/prowler/pull/10629) ### ๐Ÿ”„ Changed diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index 4b8498f7e7..83ef77ad0c 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -32,9 +32,13 @@ from prowler.lib.outputs.compliance.cis.cis_aws import AWSCIS from prowler.lib.outputs.compliance.cis.cis_azure import AzureCIS from prowler.lib.outputs.compliance.cis.cis_gcp import GCPCIS from prowler.lib.outputs.compliance.cis.cis_github import GithubCIS +from prowler.lib.outputs.compliance.cis.cis_googleworkspace import GoogleWorkspaceCIS from prowler.lib.outputs.compliance.cis.cis_kubernetes import KubernetesCIS from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS from prowler.lib.outputs.compliance.cis.cis_oraclecloud import OracleCloudCIS +from prowler.lib.outputs.compliance.cisa_scuba.cisa_scuba_googleworkspace import ( + GoogleWorkspaceCISASCuBA, +) from prowler.lib.outputs.compliance.csa.csa_alibabacloud import AlibabaCloudCSA from prowler.lib.outputs.compliance.csa.csa_aws import AWSCSA from prowler.lib.outputs.compliance.csa.csa_azure import AzureCSA @@ -133,6 +137,10 @@ COMPLIANCE_CLASS_MAP = { "github": [ (lambda name: name.startswith("cis_"), GithubCIS), ], + "googleworkspace": [ + (lambda name: name.startswith("cis_"), GoogleWorkspaceCIS), + (lambda name: name.startswith("cisa_scuba_"), GoogleWorkspaceCISASCuBA), + ], "iac": [ # IaC provider doesn't have specific compliance frameworks yet # Trivy handles its own compliance checks From 56c370d3a4102daf5b3d09b8596049b0ec3d2e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 9 Apr 2026 15:27:18 +0200 Subject: [PATCH 28/36] chore(ccc): update with latest version and improve mapping (#10625) --- api/src/backend/tasks/jobs/export.py | 6 +- prowler/CHANGELOG.md | 1 + prowler/compliance/aws/ccc_aws.json | 10286 ++++++++------- prowler/compliance/azure/ccc_azure.json | 9857 +++++++++------ prowler/compliance/gcp/ccc_gcp.json | 10463 +++++++++------- prowler/lib/outputs/compliance/ccc/ccc.py | 98 + prowler/lib/outputs/compliance/compliance.py | 10 + tests/lib/outputs/compliance/ccc/__init__.py | 0 .../outputs/compliance/ccc/ccc_aws_test.py | 138 + .../outputs/compliance/ccc/ccc_azure_test.py | 99 + .../outputs/compliance/ccc/ccc_gcp_test.py | 99 + tests/lib/outputs/compliance/fixtures.py | 167 + 12 files changed, 18378 insertions(+), 12846 deletions(-) create mode 100644 prowler/lib/outputs/compliance/ccc/ccc.py create mode 100644 tests/lib/outputs/compliance/ccc/__init__.py create mode 100644 tests/lib/outputs/compliance/ccc/ccc_aws_test.py create mode 100644 tests/lib/outputs/compliance/ccc/ccc_azure_test.py create mode 100644 tests/lib/outputs/compliance/ccc/ccc_gcp_test.py diff --git a/api/src/backend/tasks/jobs/export.py b/api/src/backend/tasks/jobs/export.py index 83ef77ad0c..3be9b81544 100644 --- a/api/src/backend/tasks/jobs/export.py +++ b/api/src/backend/tasks/jobs/export.py @@ -97,7 +97,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name.startswith("iso27001_"), AWSISO27001), (lambda name: name.startswith("kisa"), AWSKISAISMSP), (lambda name: name == "prowler_threatscore_aws", ProwlerThreatScoreAWS), - (lambda name: name == "ccc_aws", CCC_AWS), + (lambda name: name.startswith("ccc_"), CCC_AWS), (lambda name: name.startswith("c5_"), AWSC5), (lambda name: name.startswith("csa_"), AWSCSA), ], @@ -106,7 +106,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name == "mitre_attack_azure", AzureMitreAttack), (lambda name: name.startswith("ens_"), AzureENS), (lambda name: name.startswith("iso27001_"), AzureISO27001), - (lambda name: name == "ccc_azure", CCC_Azure), + (lambda name: name.startswith("ccc_"), CCC_Azure), (lambda name: name == "prowler_threatscore_azure", ProwlerThreatScoreAzure), (lambda name: name == "c5_azure", AzureC5), (lambda name: name.startswith("csa_"), AzureCSA), @@ -117,7 +117,7 @@ COMPLIANCE_CLASS_MAP = { (lambda name: name.startswith("ens_"), GCPENS), (lambda name: name.startswith("iso27001_"), GCPISO27001), (lambda name: name == "prowler_threatscore_gcp", ProwlerThreatScoreGCP), - (lambda name: name == "ccc_gcp", CCC_GCP), + (lambda name: name.startswith("ccc_"), CCC_GCP), (lambda name: name == "c5_gcp", GCPC5), (lambda name: name.startswith("csa_"), GCPCSA), ], diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index cd5e995eae..8f60b4a7d7 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `entra_conditional_access_policy_device_registration_mfa_required` check and `entra_intune_enrollment_sign_in_frequency_every_time` enhancement for M365 provider [(#10222)](https://github.com/prowler-cloud/prowler/pull/10222) - `entra_conditional_access_policy_block_elevated_insider_risk` check for M365 provider [(#10234)](https://github.com/prowler-cloud/prowler/pull/10234) - `Vercel` provider support with 30 checks [(#10189)](https://github.com/prowler-cloud/prowler/pull/10189) +- CCC improvements with the latest checks and new mappings [(#10625)](https://github.com/prowler-cloud/prowler/pull/10625) ### ๐Ÿ”„ Changed diff --git a/prowler/compliance/aws/ccc_aws.json b/prowler/compliance/aws/ccc_aws.json index 1f6da6d5f6..11aa32f4ee 100644 --- a/prowler/compliance/aws/ccc_aws.json +++ b/prowler/compliance/aws/ccc_aws.json @@ -1,10 +1,1835 @@ { "Framework": "CCC", - "Version": "", + "Version": "v2025.10", "Provider": "AWS", "Name": "Common Cloud Controls Catalog (CCC)", "Description": "Common Cloud Controls Catalog (CCC) for AWS", "Requirements": [ + { + "Id": "CCC.Core.CN01.AR01", + "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "cloudfront_distributions_https_enabled", + "cloudfront_distributions_origin_traffic_encrypted", + "cloudfront_distributions_using_deprecated_ssl_protocols", + "elb_insecure_ssl_ciphers", + "elb_ssl_listeners", + "elbv2_insecure_ssl_ciphers", + "elbv2_ssl_listeners", + "elbv2_nlb_tls_termination_enabled", + "s3_bucket_secure_transport_policy", + "opensearch_service_domains_https_communications_enforced", + "opensearch_service_domains_node_to_node_encryption_enabled", + "elasticache_redis_cluster_in_transit_encryption_enabled", + "dynamodb_accelerator_cluster_in_transit_encryption_enabled", + "dms_endpoint_ssl_enabled", + "dms_endpoint_redis_in_transit_encryption_enabled", + "kafka_cluster_in_transit_encryption_enabled", + "kafka_connector_in_transit_encryption_enabled", + "redshift_cluster_in_transit_encryption_enabled", + "rds_instance_transport_encrypted", + "transfer_server_in_transit_encryption_enabled", + "glue_database_connections_ssl_enabled", + "sns_subscription_not_using_http_endpoints" + ] + }, + { + "Id": "CCC.Core.CN01.AR02", + "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "ec2_instance_port_ssh_exposed_to_internet", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", + "ec2_networkacl_allow_ingress_tcp_port_22" + ] + }, + { + "Id": "CCC.Core.CN01.AR03", + "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "cloudfront_distributions_https_enabled", + "cloudfront_distributions_origin_traffic_encrypted", + "opensearch_service_domains_https_communications_enforced", + "transfer_server_in_transit_encryption_enabled", + "s3_bucket_secure_transport_policy", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_ftp_20_21", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23" + ] + }, + { + "Id": "CCC.Core.CN01.AR07", + "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN01.AR08", + "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "apigateway_restapi_client_certificate_enabled", + "kafka_cluster_mutual_tls_authentication_enabled" + ] + }, + { + "Id": "CCC.Core.CN13.AR01", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "acm_certificates_expiration_check", + "acm_certificates_with_secure_key_algorithms", + "acm_certificates_transparency_logs_enabled" + ] + }, + { + "Id": "CCC.Core.CN13.AR02", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "acm_certificates_expiration_check" + ] + }, + { + "Id": "CCC.Core.CN13.AR03", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "acm_certificates_expiration_check" + ] + }, + { + "Id": "CCC.Core.CN06.AR01", + "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [ + "organizations_scp_check_deny_regions" + ] + }, + { + "Id": "CCC.Core.CN06.AR02", + "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [ + "organizations_scp_check_deny_regions" + ] + }, + { + "Id": "CCC.Core.CN08.AR01", + "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_cross_region_replication", + "backup_plans_exist", + "backup_vaults_exist", + "dynamodb_table_protected_by_backup_plan", + "rds_cluster_protected_by_backup_plan", + "rds_instance_protected_by_backup_plan", + "rds_cluster_multi_az", + "rds_instance_multi_az", + "efs_multi_az_enabled", + "neptune_cluster_multi_az", + "documentdb_cluster_multi_az_enabled", + "elasticache_redis_cluster_multi_az_enabled" + ] + }, + { + "Id": "CCC.Core.CN08.AR02", + "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_cross_region_replication" + ] + }, + { + "Id": "CCC.Core.CN09.AR01", + "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "cloudwatch_log_group_not_publicly_accessible", + "cloudtrail_logs_s3_bucket_access_logging_enabled", + "cloudtrail_log_file_validation_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_bucket_requires_mfa_delete" + ] + }, + { + "Id": "CCC.Core.CN09.AR02", + "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_log_file_validation_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_cloudwatch_logging_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" + ] + }, + { + "Id": "CCC.Core.CN09.AR03", + "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_log_file_validation_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", + "cloudwatch_changes_to_network_acls_alarm_configured", + "cloudwatch_changes_to_network_gateways_alarm_configured", + "cloudwatch_changes_to_network_route_tables_alarm_configured", + "cloudwatch_changes_to_vpcs_alarm_configured" + ] + }, + { + "Id": "CCC.Core.CN10.AR01", + "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-10", + "DSP-19" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_cross_region_replication" + ] + }, + { + "Id": "CCC.Core.CN02.AR01", + "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN02 Encrypt Data for Storage", + "SubSection": "", + "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "UEM-08", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_default_encryption", + "s3_bucket_kms_encryption", + "ec2_ebs_default_encryption", + "ec2_ebs_volume_encryption", + "ec2_ebs_snapshots_encrypted", + "efs_encryption_at_rest_enabled", + "storagegateway_fileshare_encryption_enabled", + "rds_instance_storage_encrypted", + "rds_cluster_storage_encrypted", + "rds_snapshots_encrypted", + "redshift_cluster_encrypted_at_rest", + "documentdb_cluster_storage_encrypted", + "neptune_cluster_storage_encrypted", + "neptune_cluster_snapshot_encrypted", + "dynamodb_tables_kms_cmk_encryption_enabled", + "dynamodb_accelerator_cluster_encryption_enabled", + "kafka_cluster_encryption_at_rest_uses_cmk", + "kinesis_stream_encrypted_at_rest", + "firehose_stream_encrypted_at_rest", + "sns_topics_kms_encryption_at_rest_enabled", + "sqs_queues_server_side_encryption_enabled", + "opensearch_service_domains_encryption_at_rest_enabled", + "athena_workgroup_encryption", + "glue_data_catalogs_metadata_encryption_enabled", + "glue_data_catalogs_connection_passwords_encryption_enabled", + "glue_etl_jobs_amazon_s3_encryption_enabled", + "backup_vaults_encrypted", + "backup_recovery_point_encrypted", + "cloudtrail_kms_encryption_enabled", + "cloudwatch_log_group_kms_encryption_enabled", + "eks_cluster_kms_cmk_encryption_in_secrets_enabled", + "sagemaker_notebook_instance_encryption_enabled", + "apigateway_restapi_cache_encrypted" + ] + }, + { + "Id": "CCC.Core.CN11.AR01", + "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "acm_certificates_with_secure_key_algorithms" + ] + }, + { + "Id": "CCC.Core.CN11.AR02", + "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR03", + "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_are_used" + ] + }, + { + "Id": "CCC.Core.CN11.AR04", + "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "iam_inline_policy_no_full_access_to_kms", + "iam_policy_no_full_access_to_kms", + "kms_cmk_not_deleted_unintentionally" + ] + }, + { + "Id": "CCC.Core.CN11.AR05", + "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR06", + "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN14.AR01", + "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "backup_vaults_exist", + "backup_plans_exist", + "rds_instance_backup_enabled", + "neptune_cluster_backup_enabled", + "documentdb_cluster_backup_enabled" + ] + }, + { + "Id": "CCC.Core.CN14.AR02", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "backup_vaults_exist", + "backup_plans_exist", + "backup_reportplans_exist", + "backup_recovery_point_encrypted", + "rds_instance_backup_enabled", + "rds_instance_protected_by_backup_plan", + "rds_cluster_protected_by_backup_plan", + "neptune_cluster_backup_enabled", + "documentdb_cluster_backup_enabled", + "dynamodb_table_protected_by_backup_plan", + "efs_have_backup_enabled" + ] + }, + { + "Id": "CCC.Core.CN14.AR03", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "backup_vaults_exist", + "backup_plans_exist", + "rds_instance_backup_enabled", + "neptune_cluster_backup_enabled", + "documentdb_cluster_backup_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR01", + "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_user_mfa_enabled_console_access", + "iam_user_hardware_mfa_enabled", + "iam_administrator_access_with_mfa", + "cognito_user_pool_mfa_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR02", + "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "iam_no_root_access_key", + "iam_root_credentials_management_enabled", + "iam_user_no_setup_initial_access_key", + "iam_administrator_access_with_mfa", + "apigateway_restapi_authorizers_enabled", + "apigatewayv2_api_authorizers_enabled", + "apigateway_restapi_public_with_authorizer" + ] + }, + { + "Id": "CCC.Core.CN03.AR03", + "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "iam_user_mfa_enabled_console_access", + "iam_user_hardware_mfa_enabled", + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_administrator_access_with_mfa", + "cognito_user_pool_mfa_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR04", + "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "iam_no_root_access_key", + "iam_user_no_setup_initial_access_key", + "apigateway_restapi_authorizers_enabled", + "apigatewayv2_api_authorizers_enabled", + "apigateway_restapi_public_with_authorizer" + ] + }, + { + "Id": "CCC.Core.CN05.AR01", + "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "apigateway_restapi_authorizers_enabled", + "apigateway_restapi_public", + "apigateway_restapi_public_with_authorizer", + "apigatewayv2_api_authorizers_enabled", + "awslambda_function_url_public", + "awslambda_function_not_publicly_accessible", + "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", + "s3_bucket_public_access", + "s3_bucket_public_list_acl", + "s3_bucket_public_write_acl", + "s3_bucket_cross_account_access", + "s3_account_level_public_access_blocks", + "iam_policy_no_full_access_to_cloudtrail", + "iam_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_cloudtrail", + "iam_inline_policy_no_full_access_to_kms", + "iam_role_administratoraccess_policy", + "iam_group_administrator_access_policy", + "iam_user_administrator_access_policy", + "iam_policy_attached_only_to_group_or_roles", + "iam_role_cross_account_readonlyaccess_policy", + "iam_role_cross_service_confused_deputy_prevention" + ] + }, + { + "Id": "CCC.Core.CN05.AR02", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_avoid_root_usage", + "iam_user_mfa_enabled_console_access", + "iam_administrator_access_with_mfa", + "iam_group_administrator_access_policy", + "iam_role_administratoraccess_policy", + "iam_user_administrator_access_policy", + "iam_inline_policy_no_full_access_to_cloudtrail", + "iam_inline_policy_no_full_access_to_kms", + "iam_policy_no_full_access_to_cloudtrail", + "iam_policy_no_full_access_to_kms", + "iam_policy_allows_privilege_escalation", + "iam_inline_policy_allows_privilege_escalation", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_customer_unattached_policy_no_administrative_privileges", + "iam_aws_attached_policy_no_administrative_privileges", + "iam_password_policy_minimum_length_14", + "iam_password_policy_uppercase", + "iam_password_policy_lowercase", + "iam_password_policy_symbol", + "iam_password_policy_number", + "iam_password_policy_expires_passwords_within_90_days_or_less", + "iam_password_policy_reuse_24" + ] + }, + { + "Id": "CCC.Core.CN05.AR03", + "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "vpc_endpoint_services_allowed_principals_trust_boundaries", + "vpc_endpoint_connections_trust_boundaries", + "iam_role_cross_service_confused_deputy_prevention", + "iam_role_cross_account_readonlyaccess_policy", + "s3_bucket_cross_account_access", + "eventbridge_bus_cross_account_access", + "eventbridge_schema_registry_cross_account_access" + ] + }, + { + "Id": "CCC.Core.CN05.AR04", + "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "accessanalyzer_enabled", + "accessanalyzer_enabled_without_findings", + "vpc_endpoint_connections_trust_boundaries", + "vpc_endpoint_services_allowed_principals_trust_boundaries", + "s3_bucket_cross_account_access", + "s3_bucket_public_access", + "iam_administrator_access_with_mfa", + "iam_inline_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_cloudtrail", + "iam_policy_no_full_access_to_kms", + "iam_policy_no_full_access_to_cloudtrail", + "iam_policy_attached_only_to_group_or_roles" + ] + }, + { + "Id": "CCC.Core.CN05.AR05", + "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "awslambda_function_url_public", + "apigateway_restapi_public", + "s3_bucket_public_access", + "s3_bucket_policy_public_write_access", + "sns_topics_not_publicly_accessible", + "sqs_queues_not_publicly_accessible", + "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", + "ec2_networkacl_allow_ingress_any_port", + "ec2_securitygroup_default_restrict_traffic", + "vpc_endpoint_for_ec2_enabled", + "vpc_endpoint_connections_trust_boundaries", + "vpc_endpoint_services_allowed_principals_trust_boundaries" + ] + }, + { + "Id": "CCC.Core.CN05.AR06", + "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_no_root_access_key", + "iam_administrator_access_with_mfa", + "iam_user_mfa_enabled_console_access", + "iam_user_hardware_mfa_enabled", + "iam_root_credentials_management_enabled", + "iam_check_saml_providers_sts", + "iam_policy_attached_only_to_group_or_roles", + "iam_role_cross_service_confused_deputy_prevention", + "iam_role_cross_account_readonlyaccess_policy", + "vpc_endpoint_connections_trust_boundaries", + "vpc_endpoint_services_allowed_principals_trust_boundaries" + ] + }, + { + "Id": "CCC.Core.CN04.AR01", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_multi_region_enabled_logging_management_events", + "cloudtrail_cloudwatch_logging_enabled", + "cloudtrail_log_file_validation_enabled", + "cloudwatch_log_metric_filter_authentication_failures", + "cloudwatch_log_metric_filter_unauthorized_api_calls", + "cloudwatch_log_metric_filter_root_usage", + "cloudwatch_log_metric_filter_sign_in_without_mfa", + "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", + "cloudwatch_log_metric_filter_policy_changes", + "cloudwatch_log_metric_filter_security_group_changes", + "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk", + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", + "cloudwatch_changes_to_network_acls_alarm_configured", + "cloudwatch_changes_to_network_gateways_alarm_configured", + "cloudwatch_changes_to_network_route_tables_alarm_configured", + "cloudwatch_changes_to_vpcs_alarm_configured", + "config_recorder_all_regions_enabled" + ] + }, + { + "Id": "CCC.Core.CN04.AR02", + "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_s3_dataevents_write_enabled", + "cloudtrail_multi_region_enabled_logging_management_events", + "cloudtrail_cloudwatch_logging_enabled", + "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled", + "vpc_flow_logs_enabled", + "apigateway_restapi_logging_enabled", + "apigatewayv2_api_access_logging_enabled" + ] + }, + { + "Id": "CCC.Core.CN04.AR03", + "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_s3_dataevents_read_enabled", + "cloudtrail_insights_exist", + "cloudtrail_cloudwatch_logging_enabled", + "cloudtrail_multi_region_enabled", + "apigateway_restapi_logging_enabled", + "apigatewayv2_api_access_logging_enabled", + "s3_bucket_server_access_logging_enabled" + ] + }, + { + "Id": "CCC.Core.CN07.AR01", + "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_threat_detection_enumeration", + "guardduty_is_enabled", + "guardduty_no_high_severity_findings" + ] + }, + { + "Id": "CCC.Core.CN07.AR02", + "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_threat_detection_enumeration" + ] + }, { "Id": "CCC.AuditLog.CN01.AR01", "Description": "When the signature validation process is performed, then it MUST detect any modification of data.", @@ -18,13 +1843,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure hash of data is included in digital signature. ", + "Recommendation": "Ensure hash of data is included in digital signature.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -61,13 +1886,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure verification process includes a chained hash function. ", + "Recommendation": "Ensure verification process includes a chained hash function.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -110,7 +1935,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -135,17 +1960,10 @@ "Checks": [ "cloudtrail_multi_region_enabled", "cloudtrail_multi_region_enabled_logging_management_events", - "cloudtrail_insights_exist", - "cloudtrail_log_file_validation_enabled", - "cloudtrail_kms_encryption_enabled", "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_logs_s3_bucket_access_logging_enabled", "cloudtrail_s3_dataevents_read_enabled", "cloudtrail_s3_dataevents_write_enabled", - "cloudtrail_threat_detection_enumeration", - "cloudtrail_threat_detection_llm_jacking", - "cloudtrail_threat_detection_privilege_escalation" + "cloudtrail_insights_exist" ] }, { @@ -162,12 +1980,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -189,14 +2007,7 @@ } ], "Checks": [ - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudtrail_log_file_validation_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_multi_region_enabled", - "cloudtrail_insights_exist", - "s3_bucket_object_lock", - "cloudtrail_multi_region_enabled_logging_management_events" + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" ] }, { @@ -213,12 +2024,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -240,17 +2051,7 @@ } ], "Checks": [ - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_changes_to_network_acls_alarm_configured", - "cloudwatch_changes_to_network_gateways_alarm_configured", - "cloudwatch_changes_to_network_route_tables_alarm_configured", - "cloudwatch_changes_to_vpcs_alarm_configured", - "cloudwatch_log_metric_filter_policy_changes", - "cloudwatch_log_metric_filter_aws_organizations_changes", - "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", - "cloudwatch_log_metric_filter_security_group_changes", - "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk", - "cloudwatch_log_metric_filter_unauthorized_api_calls" + "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes" ] }, { @@ -267,13 +2068,13 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability. ", + "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01", - "CCC.TH09" + "CCC.Core.TH01", + "CCC.Core.TH09" ] } ], @@ -296,9 +2097,6 @@ ], "Checks": [ "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_bucket_requires_mfa_delete", - "cloudtrail_kms_encryption_enabled", "s3_bucket_server_access_logging_enabled" ] }, @@ -316,12 +2114,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure audit log exporting. ", + "Recommendation": "Configure audit log exporting.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -344,16 +2142,10 @@ } ], "Checks": [ - "cloudtrail_kms_encryption_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_bucket_requires_mfa_delete", + "cloudtrail_multi_region_enabled", "cloudtrail_s3_dataevents_read_enabled", "cloudtrail_s3_dataevents_write_enabled", - "cloudtrail_multi_region_enabled", - "cloudtrail_multi_region_enabled_logging_management_events", - "s3_bucket_cross_region_replication", - "s3_bucket_cross_account_access" + "s3_bucket_cross_region_replication" ] }, { @@ -371,13 +2163,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period. ", + "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -417,13 +2209,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket. ", + "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -462,12 +2254,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure object lock policy. ", + "Recommendation": "Configure object lock policy.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -506,12 +2298,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Review field level access controls on audit data. ", + "Recommendation": "Review field level access controls on audit data.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -537,11 +2329,8 @@ } ], "Checks": [ - "cloudtrail_kms_encryption_enabled", "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_bucket_requires_mfa_delete", - "cloudwatch_log_group_not_publicly_accessible", - "s3_bucket_public_access" + "cloudwatch_log_group_not_publicly_accessible" ] }, { @@ -559,12 +2348,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -587,7 +2376,7 @@ ], "Checks": [ "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_kms_encryption_enabled", + "s3_bucket_public_access", "s3_bucket_public_list_acl", "s3_bucket_public_write_acl" ] @@ -607,12 +2396,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -635,220 +2424,34 @@ ], "Checks": [ "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "s3_bucket_public_write_acl", - "s3_bucket_public_list_acl", "s3_bucket_public_access", + "s3_bucket_public_list_acl", + "s3_bucket_public_write_acl", "s3_bucket_policy_public_write_access" ] }, { - "Id": "CCC.Build.CN01.AR01", - "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", - "Attributes": [ - { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN01 Restrict Allowed Build Agents", - "SubSection": "", - "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [ - "codebuild_project_user_controlled_buildspec", - "codebuild_project_source_repo_url_no_sensitive_credentials", - "codebuild_project_uses_allowed_github_organizations", - "codebuild_project_not_publicly_accessible", - "codebuild_project_logging_enabled", - "codebuild_project_s3_logs_encrypted", - "codebuild_project_no_secrets_in_variables", - "codebuild_project_older_90_days" - ] - }, - { - "Id": "CCC.Build.CN02.AR01", - "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", - "Attributes": [ - { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN02 Restrict Allowed External Services for Build Triggers", - "SubSection": "", - "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [ - "codebuild_project_uses_allowed_github_organizations", - "codebuild_project_user_controlled_buildspec", - "codebuild_project_source_repo_url_no_sensitive_credentials", - "codebuild_project_not_publicly_accessible" - ] - }, - { - "Id": "CCC.Build.CN03.AR01", - "Description": "Attempt to access the build environment from an external network and verify that access is denied.", - "Attributes": [ - { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN03 Deny External Network Access for Build Environments", - "SubSection": "", - "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02", - "CCC.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-7", - "SC-5" - ] - } - ] - } - ], - "Checks": [ - "codebuild_project_not_publicly_accessible" - ] - }, - { - "Id": "CCC.CntrReg.CN01.AR01", - "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", - "Attributes": [ - { - "FamilyName": "Risk Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", - "SubSection": "", - "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.CntrReg.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "ID.RA-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "RA-5", - "SI-5" - ] - } - ] - } - ], - "Checks": [ - "ecr_registry_scan_images_on_push_enabled", - "ecr_repositories_scan_vulnerabilities_in_latest_image" - ] - }, - { - "Id": "CCC.DataWar.CN01.AR01", - "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", + "Id": "CCC.Logging.CN01.AR01", + "Description": "When a new cloud account is created, provider-level audit and network flow logging MUST be enabled by default and directed to the central sink.", "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", "SubSection": "", - "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", + "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Logging.TH07" ] } ], @@ -856,14 +2459,490 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-2", + "AU-3" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_multi_region_enabled_logging_management_events", + "vpc_flow_logs_enabled" + ] + }, + { + "Id": "CCC.Logging.CN01.AR02", + "Description": "When a new cloud compute resource is deployed, it MUST be configured to forward all relevant logs (e.g., OS, application, service logs) to the central log sink.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", + "SubSection": "", + "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-2", + "AU-3" + ] + } + ] + } + ], + "Checks": [ + "vpc_flow_logs_enabled", + "cloudtrail_cloudwatch_logging_enabled", + "apigateway_restapi_logging_enabled", + "apigatewayv2_api_access_logging_enabled", + "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled" + ] + }, + { + "Id": "CCC.Logging.CN02.AR01", + "Description": "When a new log bucket or stream is created, its retention policy MUST be configured in accordance with organisation's data retention policy.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "GV.PO-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_group_retention_policy_specific_days_enabled" + ] + }, + { + "Id": "CCC.Logging.CN02.AR02", + "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "GV.PO-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_group_retention_policy_specific_days_enabled" + ] + }, + { + "Id": "CCC.Logging.CN03.AR01", + "Description": "When an attempt is made to modify or delete data before the object lock period expires, then the action MUST be denied.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN03 Enable Object Lock On Log Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure log immutability by enabling Write Once, Read Many (WORM) protection using object lock on log storage buckets. This prevents logs from being modified or deleted during the defined retention period, supporting compliance and forensic integrity.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "Configure object lock policy.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-9", + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_lock" + ] + }, + { + "Id": "CCC.Logging.CN04.AR01", + "Description": "When restricted fields are accessed by unauthorized users, then those fields MUST remain masked.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN04 Restrict Field And Log Type Access", + "SubSection": "", + "SubSectionObjective": "Configure access to logs to follow the principle of least privilege in particular where technically possible limit the log fields users have access to to prevent accidental exposure to sensitive information such as PII.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "Review field level access controls on log data.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6", + "AU-9", + "AC-3", + "PT-2", + "PT-3", + "PT-3" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_group_not_publicly_accessible", + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible" + ] + }, + { + "Id": "CCC.Logging.CN05.AR01", + "Description": "When a log storage bucket is created, the bucket's access control settings MUST explicitly deny public read and write access.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", + "SubSection": "", + "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green" + ], + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "AC-3", - "AC-6" + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "s3_bucket_public_access", + "s3_bucket_public_list_acl", + "s3_bucket_public_write_acl", + "s3_account_level_public_access_blocks", + "s3_bucket_level_public_access_block" + ] + }, + { + "Id": "CCC.Logging.CN05.AR02", + "Description": "When the URL of a log storage bucket's object is accessed publicly, the action MUST be denied by bucket policy.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", + "SubSection": "", + "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green" + ], + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_public_access", + "s3_bucket_public_list_acl", + "s3_bucket_public_write_acl", + "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", + "s3_account_level_public_access_blocks" + ] + }, + { + "Id": "CCC.Logging.CN06.AR01", + "Description": "When a single principal executes an anomalously high number of log queries, an alert MUST be generated.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", + "Section": "CCC.Logging.CN06 Detect and Alert on Potential Log Exfiltration", + "SubSection": "", + "SubSectionObjective": "Identify and alert on anomalous data access patterns that may indicate an attempt to exfiltrate log data.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "CA-7", + "AU-6" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_threat_detection_enumeration" + ] + }, + { + "Id": "CCC.Logging.CN07.AR01", + "Description": "When an audit log event is recorded that corresponds to a modification of the logging service configuration such as disabling a log trail, deleting a log sink, or altering a log forwarding rule, an alert MUST be generated.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", + "Section": "CCC.Logging.CN07 Detect and Alert on Log Service Tampering", + "SubSection": "", + "SubSectionObjective": "Alert when any component of the critical logging infrastructure is disabled, modified, or deleted, indicating a defense evasion attempt.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "CA-7", + "AU-6" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" + ] + }, + { + "Id": "CCC.Monitor.CN01.AR01", + "Description": "When an External Monitoring system exceeds the anticipated rate of monitoring checks then Rate Limiting MUST be applied and an Audit Alert MUST be generated.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", + "Section": "CCC.Monitor.CN01 Rate Limiting on External Monitoring", + "SubSection": "", + "SubSectionObjective": "Prevent DoS attacks using External Monitoring tools.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IR-01", + "DE.CM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-5", + "SC-7" ] } ] @@ -872,25 +2951,27 @@ "Checks": [] }, { - "Id": "CCC.DataWar.CN02.AR01", - "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", + "Id": "CCC.Monitor.CN02.AR01", + "Description": "When an Custom or User-Defined Metric starts to flood a collector, then a rate limit MUST be applied to reduce the network impact of traffic and an alert must triggered.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", + "Section": "CCC.Monitor.CN02 Rate Limiting on Metric Generation", "SubSection": "", - "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", + "SubSectionObjective": "Prevent Malicious Actor or misconfiguration from flooding services with metric data.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Monitor.TH06" ] } ], @@ -898,14 +2979,15 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "DE.CM-01" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3", - "AC-6" + "SC-5(2)", + "CA-7", + "SI-4" ] } ] @@ -914,25 +2996,27 @@ "Checks": [] }, { - "Id": "CCC.DataWar.CN03.AR01", - "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", + "Id": "CCC.Monitor.CN03.AR01", + "Description": "When external systems have approved access to internal systems not normally available for public access then they MUST be secured to prevent unauthorised access jumping through to the internal systems and only allow access to specific internal services.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN03 Access External Monitoring", "SubSection": "", - "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", + "SubSectionObjective": "Control access to Synthetic monitoring solutions using API keys or Certificate based authentication to ensure they don't become an attack path, preventing monitoring systems from forging network requests to gain access to internal systems.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Monitor.TH04" ] } ], @@ -940,14 +3024,111 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "DE.CM-06", + "PR.IR-01", + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3", - "AC-6" + "AC-3" + ] + } + ] + } + ], + "Checks": [ + "apigateway_restapi_authorizers_enabled", + "apigateway_restapi_client_certificate_enabled", + "apigatewayv2_api_authorizers_enabled", + "apigateway_restapi_public_with_authorizer" + ] + }, + { + "Id": "CCC.Monitor.CN04.AR01", + "Description": "When monitoring dashboards display degraded services which may become potential targets then the dashboard MUST be protected from unauthorised access.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN04 Restrict access to Monitoring Dashboards", + "SubSection": "", + "SubSectionObjective": "Control access to Monitoring Dashboards and reports to ensure they don't highlight an attack path.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-09", + "DE.AE-03" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "AC-3" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_group_not_publicly_accessible" + ] + }, + { + "Id": "CCC.Monitor.CN05.AR01", + "Description": "When monitoring services have generated an alert, the service MUST ensure only authorised responders silence or acknowledge the alert.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN05 Restrict access to silence or acknowledge an alert", + "SubSection": "", + "SubSectionObjective": "Ensure only a subset of users can silence or acknowledge alerts to prevent attackers hiding their activity.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IR-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3" ] } ] @@ -956,179 +3137,762 @@ "Checks": [] }, { - "Id": "CCC.KeyMgmt.CN01.AR01", - "Description": "When a key version is scheduled for deletion or disabled, an alert MUST be generated within five minutes.", + "Id": "CCC.Monitor.CN06.AR01", + "Description": "When systems push metrics or traces they MUST be authenticated for that particular type of metric or trace", "Attributes": [ { - "FamilyName": "Logging and Metrics Publication", - "FamilyDescription": "Controls that collect, alert, and retain key-management events.", - "Section": "CCC.KeyMgmt.CN01 Alert on Key-version Changes", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN06 Metrics pushed for authorised services only", "SubSection": "", - "SubSectionObjective": "Generate near-real-time alerts when a KMS key version is disabled or scheduled for deletion, enabling rapid investigation and recovery.", + "SubSectionObjective": "Use IAM to control which types of metrics or traces can be pushed by different system to avoid a compromised system pushing fabricated metrics about a different service", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-5" + ] + } + ] + } + ], + "Checks": [ + "apigateway_restapi_authorizers_enabled", + "apigatewayv2_api_authorizers_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR01", + "Description": "When a request is made to read a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", "Applicability": [ "tlp-amber", "tlp-red" ], - "Recommendation": "Use native event services (e.g., CloudWatch Events, Azure Monitor, Cloud Audit Logs) to route notifications to an incident-response channel.", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.KeyMgmt.TH01" + "CCC.Core.TH01", + "CCC.Core.TH06" ] } ], "SectionGuidelineMappings": [ { - "ReferenceId": "NIST-CSF", + "ReferenceId": "CCM", "Identifiers": [ - "RS.AN-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IR-5" + "IAM-01", + "IAM-03", + "DSP-17" ] } ] } ], "Checks": [ - "kms_cmk_not_deleted_unintentionally" + "s3_bucket_kms_encryption", + "iam_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_kms", + "kms_key_not_publicly_accessible" ] }, { - "Id": "CCC.KeyMgmt.CN02.AR01", - "Description": "When IAM roles and key policies are reviewed, Decrypt permission MUST be granted exclusively to documented authorised principals.", + "Id": "CCC.ObjStor.CN01.AR02", + "Description": "When a request is made to read an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_kms_encryption", + "iam_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_kms", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR03", + "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_kms_encryption", + "iam_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_kms", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR04", + "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_kms_encryption", + "iam_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_kms", + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR01", + "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_lock", + "s3_bucket_object_versioning" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR02", + "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR01", + "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR02", + "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR01", + "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_versioning" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR02", + "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_versioning" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR03", + "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_versioning" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR04", + "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_object_versioning" + ] + }, + { + "Id": "CCC.ObjStor.CN07.AR01", + "Description": "The object storage service MUST support a configuration option that requires MFA to be successfully completed before any object deletion can be attempted, regardless of the request interface.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_no_mfa_delete" + ] + }, + { + "Id": "CCC.ObjStor.CN07.AR02", + "Description": "When MFA deletion protection is enabled on a bucket or object namespace, the service MUST deny any deletion request from an identity that has not satisfied the MFA requirement at the time of the request.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_no_mfa_delete" + ] + }, + { + "Id": "CCC.ObjStor.CN07.AR03", + "Description": "When an attempt is made to delete an object, the service's audit logs MUST clearly record each deletion attempt, including whether MFA was required and whether validation was met.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [ + "s3_bucket_no_mfa_delete" + ] + }, + { + "Id": "CCC.ObjStor.CN02.AR01", + "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that enforce least-privilege use of KMS operations.", - "Section": "CCC.KeyMgmt.CN02 Limit Decrypt Permissions", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", "SubSection": "", - "SubSectionObjective": "Restrict the Decrypt operation to authorised principals only, applying the principle of least privilege to protect sensitive data.", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", "Applicability": [ - "tlp-green" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], - "Recommendation": "Periodically audit policy documents via automated tooling and report any deviations.", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.KeyMgmt.TH02" + "CCC.Core.TH01" ] } ], "SectionGuidelineMappings": [ { - "ReferenceId": "NIST-CSF", + "ReferenceId": "CCM", "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-6" + "IAM-08" ] } ] } ], "Checks": [ - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_not_multi_region", - "kms_cmk_rotation_enabled", - "kms_cmk_are_used", - "iam_inline_policy_no_full_access_to_kms" + "s3_bucket_acl_prohibited" ] }, { - "Id": "CCC.KeyMgmt.CN03.AR01", - "Description": "When rotation settings are examined, rotation MUST be enabled with an interval not exceeding 365 days.", + "Id": "CCC.ObjStor.CN02.AR02", + "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", "Attributes": [ { - "FamilyName": "Key Lifecycle Management", - "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", - "Section": "CCC.KeyMgmt.CN03 Enforce Automatic Rotation", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", "SubSection": "", - "SubSectionObjective": "Ensure symmetric keys rotate automatically within policy intervals to reduce exposure of key material.", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", "Applicability": [ - "tlp-green" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], - "Recommendation": "Use cloud-provider rotation features and verify via configuration scanning.", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.KeyMgmt.TH03" + "CCC.Core.TH01" ] } ], "SectionGuidelineMappings": [ { - "ReferenceId": "NIST-CSF", + "ReferenceId": "CCM", "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12" + "IAM-08" ] } ] } ], "Checks": [ - "kms_cmk_rotation_enabled" - ] - }, - { - "Id": "CCC.KeyMgmt.CN04.AR01", - "Description": "When a key import request is processed, the key MUST use an approved algorithm (RSA-2048+, EC-P256+) and originate from a certified HSM.", - "Attributes": [ - { - "FamilyName": "Key Lifecycle Management", - "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", - "Section": "CCC.KeyMgmt.CN04 Validate Imported Keys", - "SubSection": "", - "SubSectionObjective": "Accept only externally generated keys that meet approved cryptographic strength and provenance requirements.", - "Applicability": [ - "tlp-green" - ], - "Recommendation": "Implement an approval workflow that validates attestation data before import.", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.KeyMgmt.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_rotation_enabled", - "kms_cmk_not_multi_region", - "kms_cmk_are_used" + "s3_bucket_acl_prohibited" ] }, { @@ -1136,8 +3900,8 @@ "Description": "When a single client sends more than 2000 requests within any 5-minute sliding window, the load balancer MUST throttle all subsequent requests from that client for at least 60 seconds.", "Attributes": [ { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", "SubSection": "", "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", @@ -1146,7 +3910,7 @@ "tlp-amber", "tlp-red" ], - "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests. ", + "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests.", "SectionThreatMappings": [ { "ReferenceId": "LB", @@ -1177,9 +3941,9 @@ } ], "Checks": [ - "elbv2_logging_enabled", - "elb_logging_enabled", - "vpc_flow_logs_enabled" + "wafv2_webacl_with_rules", + "waf_regional_webacl_with_rules", + "waf_global_webacl_with_rules" ] }, { @@ -1187,8 +3951,8 @@ "Description": "When throttling is invoked, the load balancer MUST record the event in the access log within 5 minutes for alerting and trend analysis.", "Attributes": [ { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", "SubSection": "", "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", @@ -1197,7 +3961,7 @@ "tlp-amber", "tlp-red" ], - "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts. ", + "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts.", "SectionThreatMappings": [ { "ReferenceId": "LB", @@ -1228,9 +3992,10 @@ } ], "Checks": [ + "wafv2_webacl_logging_enabled", + "waf_global_webacl_logging_enabled", "elbv2_logging_enabled", - "elb_logging_enabled", - "vpc_flow_logs_enabled" + "elb_logging_enabled" ] }, { @@ -1238,8 +4003,8 @@ "Description": "When more than 10 percent of targets change from healthy to unhealthy within five minutes, an alert MUST be issued.", "Attributes": [ { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", "Section": "CCC.LB.CN06 Secure Health-Check Telemetry", "SubSection": "", "SubSectionObjective": "Monitor health-check endpoints for tampering and alert on abnormal status changes.", @@ -1248,7 +4013,7 @@ "tlp-amber", "tlp-red" ], - "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets. ", + "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets.", "SectionThreatMappings": [ { "ReferenceId": "LB", @@ -1276,9 +4041,7 @@ "Checks": [ "elbv2_logging_enabled", "elb_logging_enabled", - "cloudwatch_alarm_actions_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "vpc_flow_logs_enabled" + "cloudwatch_alarm_actions_enabled" ] }, { @@ -1287,7 +4050,7 @@ "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", "Section": "CCC.LB.CN04 Enforce Distribution Policies", "SubSection": "", "SubSectionObjective": "Ensure traffic-splitting weights and algorithms are modified only by trusted identities.", @@ -1296,7 +4059,7 @@ "tlp-amber", "tlp-red" ], - "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging. ", + "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging.", "SectionThreatMappings": [ { "ReferenceId": "LB", @@ -1323,11 +4086,7 @@ ], "Checks": [ "cloudtrail_cloudwatch_logging_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "iam_policy_attached_only_to_group_or_roles", - "iam_group_administrator_access_policy", - "iam_role_administratoraccess_policy", - "iam_user_administrator_access_policy" + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" ] }, { @@ -1336,7 +4095,7 @@ "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", "Section": "CCC.LB.CN05 Validate Session Affinity", "SubSection": "", "SubSectionObjective": "Configure session persistence to minimise fixation and hijacking risks.", @@ -1345,7 +4104,7 @@ "tlp-amber", "tlp-red" ], - "Recommendation": "Audit CCC.LB.F15 parameters via configuration scans.", + "Recommendation": "Audit CCC.LB.CP15 parameters via configuration scans.", "SectionThreatMappings": [ { "ReferenceId": "LB", @@ -1370,22 +4129,7 @@ ] } ], - "Checks": [ - "iam_user_administrator_access_policy", - "iam_group_administrator_access_policy", - "iam_role_administratoraccess_policy", - "iam_inline_policy_allows_privilege_escalation", - "iam_inline_policy_no_full_access_to_cloudtrail", - "iam_inline_policy_no_full_access_to_kms", - "iam_inline_policy_no_administrative_privileges", - "iam_policy_allows_privilege_escalation", - "iam_customer_attached_policy_no_administrative_privileges", - "iam_aws_attached_policy_no_administrative_privileges", - "iam_policy_no_full_access_to_cloudtrail", - "iam_policy_no_full_access_to_kms", - "iam_customer_unattached_policy_no_administrative_privileges", - "iam_policy_attached_only_to_group_or_roles" - ] + "Checks": [] }, { "Id": "CCC.LB.CN09.AR01", @@ -1393,7 +4137,7 @@ "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", "Section": "CCC.LB.CN09 Restrict Management API Access", "SubSection": "", "SubSectionObjective": "Limit load-balancer API calls to authorised identities and trusted networks.", @@ -1429,8 +4173,7 @@ ], "Checks": [ "vpc_endpoint_services_allowed_principals_trust_boundaries", - "vpc_endpoint_connections_trust_boundaries", - "vpc_endpoint_for_ec2_enabled" + "vpc_endpoint_connections_trust_boundaries" ] }, { @@ -1439,7 +4182,7 @@ "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", "Section": "CCC.LB.CN02 Auto-Scale Load Balancer Capacity", "SubSection": "", "SubSectionObjective": "Expand load-balancer capacity to maintain availability during traffic spikes.", @@ -1476,9 +4219,7 @@ "Checks": [ "autoscaling_group_capacity_rebalance_enabled", "autoscaling_group_elb_health_check_enabled", - "autoscaling_group_multiple_az", - "autoscaling_group_multiple_instance_types", - "autoscaling_group_using_ec2_launch_template" + "autoscaling_group_multiple_az" ] }, { @@ -1487,7 +4228,7 @@ "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", "Section": "CCC.LB.CN07 Scrub Sensitive Headers", "SubSection": "", "SubSectionObjective": "Remove headers that disclose internal details or software versions from HTTP responses.", @@ -1501,7 +4242,7 @@ { "ReferenceId": "LB", "Identifiers": [ - "CCC.TH15" + "CCC.Core.TH15" ] } ], @@ -1564,1733 +4305,7 @@ } ], "Checks": [ - "acm_certificates_expiration_check", - "acm_certificates_transparency_logs_enabled", - "acm_certificates_with_secure_key_algorithms" - ] - }, - { - "Id": "CCC.Logging.CN01.AR01", - "Description": "When a new cloud account is created, provider-level audit and network flow logging MUST be enabled by default and directed to the central sink.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", - "SubSection": "", - "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_multi_region_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_log_file_validation_enabled", - "vpc_flow_logs_enabled", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "apigateway_restapi_logging_enabled", - "apigateway_restapi_authorizers_enabled", - "apigateway_restapi_public", - "apigatewayv2_api_access_logging_enabled" - ] - }, - { - "Id": "CCC.Logging.CN01.AR02", - "Description": "When a new cloud compute resource is deployed, it MUST be configured to forward all relevant logs (e.g., OS, application, service logs) to the central log sink.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", - "SubSection": "", - "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3" - ] - } - ] - } - ], - "Checks": [ - "vpc_flow_logs_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_multi_region_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "apigateway_restapi_logging_enabled", - "apigatewayv2_api_access_logging_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", - "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible" - ] - }, - { - "Id": "CCC.Logging.CN02.AR01", - "Description": "When a new log bucket or stream is created, its retention policy MUST be configured in accordance with organisation's data retention policy.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "GV.PO-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "cloudwatch_log_group_retention_policy_specific_days_enabled" - ] - }, - { - "Id": "CCC.Logging.CN02.AR02", - "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "GV.PO-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "cloudwatch_log_group_retention_policy_specific_days_enabled" - ] - }, - { - "Id": "CCC.AuditLog.CN08.AR01", - "Description": "When an attempt is made to modify or delete data before the object lock period expires, then the action MUST be denied.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN03 Enable Object Lock On Log Bucket", - "SubSection": "", - "SubSectionObjective": "Ensure log immutability by enabling Write Once, Read Many (WORM) protection using object lock on log storage buckets. This prevents logs from being modified or deleted during the defined retention period, supporting compliance and forensic integrity.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "Configure object lock policy. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9", - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_lock" - ] - }, - { - "Id": "CCC.AuditLog.CN04.AR01", - "Description": "When restricted fields are accessed by unauthorized users, then those fields MUST remain masked.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN04 Restrict Field And Log Type Access", - "SubSection": "", - "SubSectionObjective": "Configure access to logs to follow the principle of least privilege in particular where technically possible limit the log fields users have access to to prevent accidental exposure to sensitive information such as PII.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "Review field level access controls on log data. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-6", - "AU-9", - "AC-3", - "PT-2", - "PT-3", - "PT-3" - ] - } - ] - } - ], - "Checks": [ - "cloudwatch_log_group_not_publicly_accessible", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible" - ] - }, - { - "Id": "CCC.Logging.CN05.AR01", - "Description": "When a log storage bucket is created, the bucket's access control settings MUST explicitly deny public read and write access.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", - "SubSection": "", - "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", - "Applicability": [ - "tlp-red", - "tlp-amber", - "tlp-green" - ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_multi_region_enabled", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_kms_encryption_enabled", - "s3_bucket_public_list_acl", - "s3_bucket_public_write_acl", - "s3_bucket_public_access", - "s3_account_level_public_access_blocks", - "s3_bucket_level_public_access_block" - ] - }, - { - "Id": "CCC.Logging.CN05.AR02", - "Description": "When the URL of a log storage bucket's object is accessed publicly, the action MUST be denied by bucket policy.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", - "SubSection": "", - "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", - "Applicability": [ - "tlp-red", - "tlp-amber", - "tlp-green" - ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_public_access", - "s3_bucket_public_list_acl", - "s3_bucket_public_write_acl", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "s3_bucket_cross_region_replication", - "s3_account_level_public_access_blocks" - ] - }, - { - "Id": "CCC.Logging.CN06.AR01", - "Description": "When a single principal executes an anomalously high number of log queries, an alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", - "Section": "CCC.Logging.CN06 Detect and Alert on Potential Log Exfiltration", - "SubSection": "", - "SubSectionObjective": "Identify and alert on anomalous data access patterns that may indicate an attempt to exfiltrate log data.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-03", - "DE.CM-09" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "CA-7", - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_threat_detection_enumeration", - "cloudtrail_threat_detection_privilege_escalation" - ] - }, - { - "Id": "CCC.Logging.CN07.AR01", - "Description": "When an audit log event is recorded that corresponds to a modification of the logging service configuration such as disabling a log trail, deleting a log sink, or altering a log forwarding rule, an alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", - "Section": "CCC.Logging.CN07 Detect and Alert on Log Service Tampering", - "SubSection": "", - "SubSectionObjective": "Alert when any component of the critical logging infrastructure is disabled, modified, or deleted, indicating a defense evasion attempt.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-03", - "DE.CM-09" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "CA-7", - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_insights_exist", - "cloudtrail_log_file_validation_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudtrail_multi_region_enabled_logging_management_events", - "cloudwatch_changes_to_network_acls_alarm_configured", - "cloudwatch_changes_to_network_gateways_alarm_configured", - "cloudwatch_changes_to_network_route_tables_alarm_configured", - "cloudwatch_changes_to_vpcs_alarm_configured" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR01", - "Description": "When a request is made to read a protected bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_kms_encryption", - "kms_key_not_publicly_accessible", - "iam_policy_no_full_access_to_kms", - "storagegateway_fileshare_encryption_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR02", - "Description": "When a request is made to read a protected object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_cmk_not_deleted_unintentionally", - "iam_policy_no_full_access_to_kms", - "iam_inline_policy_no_full_access_to_kms" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR03", - "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_kms_encryption", - "iam_policy_no_full_access_to_kms", - "kms_key_not_publicly_accessible", - "kms_cmk_not_deleted_unintentionally", - "storagegateway_fileshare_encryption_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR04", - "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "iam_policy_no_full_access_to_kms", - "iam_inline_policy_no_full_access_to_kms", - "kms_cmk_not_deleted_unintentionally", - "kms_key_not_publicly_accessible", - "kms_cmk_not_multi_region" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR01", - "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "s3_bucket_object_lock", - "s3_bucket_lifecycle_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR02", - "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "s3_bucket_lifecycle_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN04.AR01", - "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "kinesis_stream_data_retention_period", - "s3_bucket_object_versioning", - "s3_bucket_object_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN04.AR02", - "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "kinesis_stream_data_retention_period", - "dynamodb_table_deletion_protection_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR01", - "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "s3_bucket_object_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR02", - "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "s3_bucket_object_lock", - "iam_rotate_access_key_90_days", - "ecr_repositories_tag_immutability" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR03", - "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "dynamodb_tables_pitr_enabled", - "backup_recovery_point_encrypted" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR04", - "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_object_versioning", - "kinesis_stream_data_retention_period", - "kms_cmk_not_deleted_unintentionally" - ] - }, - { - "Id": "CCC.ObjStor.CN06.AR01", - "Description": "When an object storage bucket is accessed, the service MUST store access logs in a separate data store.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN06 Prevent Deployment in Restricted Regions", - "SubSection": "CCC.ObjStor.C06 Access Logs are Stored in a Separate Data Store", - "SubSectionObjective": "Ensure that access logs for object storage buckets are stored in a separate data store to protect against unauthorized access, tampering, or deletion of logs (Logbuckets are exempt from this requirement, but must be tlp-red).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH07", - "CCC.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-07", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.15.0" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "s3_bucket_server_access_logging_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN02.AR01", - "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_public_write_acl" - ] - }, - { - "Id": "CCC.ObjStor.CN02.AR02", - "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_public_write_acl", - "s3_bucket_acl_prohibited", - "s3_bucket_public_access" - ] - }, - { - "Id": "CCC.Monitor.CN01.AR01", - "Description": "When an External Monitoring system exceeds the anticipated rate of monitoring checks then Rate Limiting MUST be applied and an Audit Alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", - "Section": "CCC.Monitor.CN01 Rate Limiting on External Monitoring", - "SubSection": "", - "SubSectionObjective": "Prevent DoS attacks using External Monitoring tools.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.IR-01", - "DE.CM-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-5", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_threat_detection_enumeration", - "cloudtrail_threat_detection_llm_jacking", - "cloudtrail_threat_detection_privilege_escalation", - "cloudtrail_cloudwatch_logging_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_alarm_actions_alarm_state_configured", - "cloudtrail_multi_region_enabled_logging_management_events" - ] - }, - { - "Id": "CCC.Monitor.CN02.AR01", - "Description": "When an Custom or User-Defined Metric starts to flood a collector, then a rate limit MUST be applied to reduce the network impact of traffic and an alert must triggered.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", - "Section": "CCC.Monitor.CN02 Rate Limiting on Metric Generation", - "SubSection": "", - "SubSectionObjective": "Prevent Malicious Actor or misconfiguration from flooding services with metric data.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-5(2)", - "CA-7", - "SI-4" - ] - } - ] - } - ], - "Checks": [ - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", - "cloudwatch_changes_to_network_acls_alarm_configured", - "cloudwatch_changes_to_network_gateways_alarm_configured", - "cloudwatch_changes_to_network_route_tables_alarm_configured", - "cloudwatch_changes_to_vpcs_alarm_configured", - "cloudwatch_alarm_actions_enabled", - "cloudwatch_alarm_actions_alarm_state_configured", - "cloudwatch_log_metric_filter_authentication_failures", - "cloudwatch_log_metric_filter_unauthorized_api_calls", - "cloudwatch_log_metric_filter_policy_changes", - "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", - "cloudwatch_log_metric_filter_security_group_changes" - ] - }, - { - "Id": "CCC.Monitor.CN03.AR01", - "Description": "When external systems have approved access to internal systems not normally available for public access then they MUST be secured to prevent unauthorised access jumping through to the internal systems and only allow access to specific internal services.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN03 Access External Monitoring", - "SubSection": "", - "SubSectionObjective": "Control access to Synthetic monitoring solutions using API keys or Certificate based authentication to ensure they don't become an attack path, preventing monitoring systems from forging network requests to gain access to internal systems.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-06", - "PR.IR-01", - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "awslambda_function_url_public", - "apigateway_restapi_public", - "apigateway_restapi_authorizers_enabled", - "apigateway_restapi_public_with_authorizer", - "apigateway_restapi_client_certificate_enabled", - "apigatewayv2_api_authorizers_enabled" - ] - }, - { - "Id": "CCC.Monitor.CN04.AR01", - "Description": "When monitoring dashboards display degraded services which may become potential targets then the dashboard MUST be protected from unauthorised access.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN04 Restrict access to Monitoring Dashboards", - "SubSection": "", - "SubSectionObjective": "Control access to Monitoring Dashboards and reports to ensure they don't highlight an attack path.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-09", - "DE.AE-03" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "cloudwatch_log_group_not_publicly_accessible", - "cloudwatch_log_group_kms_encryption_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_cloudwatch_logging_enabled" - ] - }, - { - "Id": "CCC.Monitor.CN05.AR01", - "Description": "When monitoring services have generated an alert, the service MUST ensure only authorised responders silence or acknowledge the alert.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN05 Restrict access to silence or acknowledge an alert", - "SubSection": "", - "SubSectionObjective": "Ensure only a subset of users can silence or acknowledge alerts to prevent attackers hiding their activity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH10" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.IR-01", - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "iam_administrator_access_with_mfa", - "iam_root_mfa_enabled", - "iam_group_administrator_access_policy", - "iam_policy_attached_only_to_group_or_roles", - "iam_inline_policy_allows_privilege_escalation", - "iam_inline_policy_no_full_access_to_cloudtrail" - ] - }, - { - "Id": "CCC.Monitor.CN06.AR01", - "Description": "When systems push metrics or traces they MUST be authenticated for that particular type of metric or trace", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN06 Metrics pushed for authorised services only", - "SubSection": "", - "SubSectionObjective": "Use IAM to control which types of metrics or traces can be pushed by different system to avoid a compromised system pushing fabricated metrics about a different service", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-5" - ] - } - ] - } - ], - "Checks": [ - "awslambda_function_url_public", - "awslambda_function_not_publicly_accessible", - "apigateway_restapi_authorizers_enabled", - "apigatewayv2_api_authorizers_enabled", - "apigateway_restapi_public_with_authorizer", - "apigateway_restapi_public", - "cloudwatch_log_group_not_publicly_accessible" + "acm_certificates_expiration_check" ] }, { @@ -3345,11 +4360,61 @@ } ], "Checks": [ - "ec2_securitygroup_default_restrict_traffic", - "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", - "ec2_securitygroup_allow_ingress_from_internet_to_any_port" + "ec2_securitygroup_default_restrict_traffic" ] }, + { + "Id": "CCC.VPC.CN02.AR01", + "Description": "When a resource is created in a public subnet, that resource MUST NOT be assigned an external IP address by default.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN02 Limit Resource Creation in Public Subnet", + "SubSection": "", + "SubSectionObjective": "Restrict the creation of resources in the public subnet with direct access to the internet to minimize attack surfaces.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.VPC.CN03.AR01", "Description": "When a VPC peering connection is requested, the service MUST prevent connections from VPCs that are not explicitly allowed.", @@ -3461,6 +4526,390 @@ "vpc_flow_logs_enabled" ] }, + { + "Id": "CCC.KeyMgmt.CN01.AR01", + "Description": "When a key version is scheduled for deletion or disabled, an alert MUST be generated within five minutes.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain key-management events.", + "Section": "CCC.KeyMgmt.CN01 Alert on Key-version Changes", + "SubSection": "", + "SubSectionObjective": "Generate near-real-time alerts when a KMS key version is disabled or scheduled for deletion, enabling rapid investigation and recovery.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use native event services (e.g., CloudWatch Events, Azure Monitor, Cloud Audit Logs) to route notifications to an incident-response channel.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "RS.AN-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IR-5" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_not_deleted_unintentionally", + "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk" + ] + }, + { + "Id": "CCC.KeyMgmt.CN02.AR01", + "Description": "When IAM roles and key policies are reviewed, Decrypt permission MUST be granted exclusively to documented authorised principals.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that enforce least-privilege use of KMS operations.", + "Section": "CCC.KeyMgmt.CN02 Limit Decrypt Permissions", + "SubSection": "", + "SubSectionObjective": "Restrict the Decrypt operation to authorised principals only, applying the principle of least privilege to protect sensitive data.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Periodically audit policy documents via automated tooling and report any deviations.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_inline_policy_no_full_access_to_kms", + "iam_policy_no_full_access_to_kms" + ] + }, + { + "Id": "CCC.KeyMgmt.CN03.AR01", + "Description": "When rotation settings are examined, rotation MUST be enabled with an interval not exceeding 365 days.", + "Attributes": [ + { + "FamilyName": "Key Lifecycle Management", + "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", + "Section": "CCC.KeyMgmt.CN03 Enforce Automatic Rotation", + "SubSection": "", + "SubSectionObjective": "Ensure symmetric keys rotate automatically within policy intervals to reduce exposure of key material.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Use cloud-provider rotation features and verify via configuration scanning.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-12" + ] + } + ] + } + ], + "Checks": [ + "kms_cmk_rotation_enabled" + ] + }, + { + "Id": "CCC.KeyMgmt.CN04.AR01", + "Description": "When a key import request is processed, the key MUST use an approved algorithm (RSA-2048+, EC-P256+) and originate from a certified HSM.", + "Attributes": [ + { + "FamilyName": "Key Lifecycle Management", + "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", + "Section": "CCC.KeyMgmt.CN04 Validate Imported Keys", + "SubSection": "", + "SubSectionObjective": "Accept only externally generated keys that meet approved cryptographic strength and provenance requirements.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Implement an approval workflow that validates attestation data before import.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-28" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.SecMgmt.CN01.AR01", + "Description": "Attempt to use an outdated version of a secret after its rotation period has passed and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN01 Enforce Automatic Secret Rotation", + "SubSection": "", + "SubSectionObjective": "Ensure that secrets are automatically rotated on a defined schedule to reduce the risk of secret compromise and unauthorized access.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH14" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-12", + "SC-28" + ] + } + ] + } + ], + "Checks": [ + "secretsmanager_automatic_rotation_enabled", + "secretsmanager_secret_rotated_periodically" + ] + }, + { + "Id": "CCC.SecMgmt.CN02.AR01", + "Description": "Attempt to retrieve a secret from an unauthorized region and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN02 Enforce Secret Replication Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that secrets are replicated only to authorized locations as per organizational data residency and compliance requirements.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN01.AR01", + "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", + "SubSection": "", + "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN02.AR01", + "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN03.AR01", + "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.Vector.CN01.AR01", "Description": "When a vector embedding is submitted for indexing, the system MUST validate that it matches expected schema, dimension, and format profiles.", @@ -3484,7 +4933,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH05", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3523,7 +4972,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH04", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3538,17 +4987,9 @@ } ], "Checks": [ - "iam_group_administrator_access_policy", - "iam_user_administrator_access_policy", - "iam_role_administratoraccess_policy", - "iam_administrator_access_with_mfa", - "iam_inline_policy_allows_privilege_escalation", - "iam_inline_policy_no_full_access_to_cloudtrail", - "iam_inline_policy_no_full_access_to_kms", - "iam_policy_attached_only_to_group_or_roles", - "iam_customer_attached_policy_no_administrative_privileges", - "iam_customer_unattached_policy_no_administrative_privileges", - "iam_no_custom_policy_permissive_role_assumption" + "opensearch_service_domains_access_control_enabled", + "opensearch_service_domains_internal_user_database_enabled", + "iam_role_administratoraccess_policy" ] }, { @@ -3571,7 +5012,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH03", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3610,7 +5051,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH02", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3646,8 +5087,8 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH04", - "CCC.TH09", - "CCC.TH04" + "CCC.Core.TH09", + "CCC.Core.TH04" ] } ], @@ -3685,7 +5126,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH05", - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -3730,457 +5171,25 @@ "Checks": [] }, { - "Id": "CCC.Core.CN01.AR01", - "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Id": "CCC.RDMS.CN01.AR02", + "Description": "When an attempt is made to authenticate to the database using known default credentials, the authentication attempt must fail and no access should be granted.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN01 Password Management", "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudfront_distributions_origin_traffic_encrypted", - "cloudfront_distributions_https_enabled", - "cloudfront_distributions_https_sni_enabled", - "s3_bucket_secure_transport_policy", - "dms_endpoint_redis_in_transit_encryption_enabled", - "kafka_cluster_in_transit_encryption_enabled", - "transfer_server_in_transit_encryption_enabled", - "redshift_cluster_in_transit_encryption_enabled", - "rds_instance_transport_encrypted" - ] - }, - { - "Id": "CCC.Core.CN01.AR02", - "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "ec2_instance_port_ssh_exposed_to_internet", - "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", - "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", - "ec2_networkacl_allow_ingress_tcp_port_22" - ] - }, - { - "Id": "CCC.Core.CN01.AR03", - "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudfront_distributions_https_enabled", - "cloudfront_distributions_https_sni_enabled", - "cloudfront_distributions_origin_traffic_encrypted", - "opensearch_service_domains_https_communications_enforced", - "transfer_server_in_transit_encryption_enabled", - "s3_bucket_secure_transport_policy", - "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_ftp_20_21", - "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_telnet_23" - ] - }, - { - "Id": "CCC.Core.CN01.AR07", - "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudfront_distributions_origin_traffic_encrypted", - "rds_instance_transport_encrypted", - "redshift_cluster_in_transit_encryption_enabled", - "kafka_cluster_in_transit_encryption_enabled", - "transfer_server_in_transit_encryption_enabled", - "dms_endpoint_redis_in_transit_encryption_enabled", - "dms_endpoint_ssl_enabled", - "s3_bucket_secure_transport_policy" - ] - }, - { - "Id": "CCC.Core.CN01.AR08", - "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "apigateway_restapi_client_certificate_enabled", - "cloudfront_distributions_custom_ssl_certificate", - "cloudfront_distributions_https_sni_enabled", - "cloudfront_distributions_origin_traffic_encrypted", - "acm_certificates_expiration_check", - "acm_certificates_with_secure_key_algorithms", - "acm_certificates_transparency_logs_enabled", - "s3_bucket_secure_transport_policy", - "dms_endpoint_ssl_enabled", - "dms_endpoint_redis_in_transit_encryption_enabled", - "transfer_server_in_transit_encryption_enabled", - "kafka_cluster_in_transit_encryption_enabled", - "kafka_cluster_mutual_tls_authentication_enabled" - ] - }, - { - "Id": "CCC.Core.CN13.AR01", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "acm_certificates_expiration_check", - "acm_certificates_transparency_logs_enabled", - "acm_certificates_with_secure_key_algorithms" - ] - }, - { - "Id": "CCC.Core.CN13.AR02", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "SubSectionObjective": "Ensure default vendor-supplied DB administrator credentials are replaced with strong, unique passwords and that these credentials are properly managed using a secure password or secrets management solution.", "Applicability": [ + "tlp-red", "tlp-amber" ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "acm_certificates_expiration_check" - ] - }, - { - "Id": "CCC.Core.CN13.AR03", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "acm_certificates_expiration_check" - ] - }, - { - "Id": "CCC.Core.CN06.AR01", - "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", - "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH01" ] } ], @@ -4188,19 +5197,92 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.AA-01" ] }, { - "ReferenceId": "CCM", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "DSP-19" + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "rds_cluster_default_admin", + "rds_instance_default_admin" + ] + }, + { + "Id": "CCC.RDMS.CN02.AR01", + "Description": "When repeated failed login attempts are made in a short timeframe, the account must be locked out or rate-limited to prevent further login attempts.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN02 Account Lockout and Rate-Limiting", + "SubSection": "", + "SubSectionObjective": "Ensure the database enforces lockouts or rate-limiting after a specified number of failed authentication attempts. This prevents brute force or password-guessing attacks from succeeding.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-1" ] }, { - "ReferenceId": "ISO_27001", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "2013 A.11.1.1" + "AC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN04.AR01", + "Description": "When there is an attempt to perform a backup or restore, then the attempt must fail with an access denied message if credentials or roles that are not explicitly authorized for backup/restore functions.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN04 Access Control for Backup and Restore Operations", + "SubSection": "", + "SubSectionObjective": "Restrict who can initiate, manage, and validate database backup or restore operations through strict role-based or least-privilege access. Prevents accidental or malicious restorations, protecting data integrity and availability.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" ] }, { @@ -4213,33 +5295,30 @@ } ], "Checks": [ - "organizations_scp_check_deny_regions", - "vpc_endpoint_connections_trust_boundaries", - "vpc_endpoint_services_allowed_principals_trust_boundaries" + "iam_inline_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges" ] }, { - "Id": "CCC.Core.CN06.AR02", - "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Id": "CCC.RDMS.CN05.AR01", + "Description": "When an attempt is made to share a snapshot with an unauthorized account, the sharing request must be denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN05 Restrict Snapshot Sharing to Authorized Accounts", "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Ensure database snapshots can only be shared with explicitly authorized accounts, thereby minimizing the risk of data exposure or exfiltration.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH05" ] } ], @@ -4247,24 +5326,105 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-19" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.11.1.1" + "PR.DS-10" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [ + "rds_snapshots_public_access", + "neptune_cluster_public_snapshot", + "documentdb_cluster_public_snapshot", + "ec2_ami_public" + ] + }, + { + "Id": "CCC.RDMS.CN03.AR01", + "Description": "When backups are disabled, paused, or fail to run as scheduled, an alert must be triggered and logged.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN03 Enforce and Monitor Automated Backups", + "SubSection": "", + "SubSectionObjective": "Ensure database backups are automatically scheduled, actively monitored, and promptly reported if any disruptions occur. This helps maintain data integrity, facilitates disaster recovery, and supports business continuity when a system failure or breach occurs.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "CP-9" + ] + } + ] + } + ], + "Checks": [ + "rds_instance_backup_enabled", + "rds_cluster_critical_event_subscription", + "neptune_cluster_backup_enabled", + "documentdb_cluster_backup_enabled" + ] + }, + { + "Id": "CCC.Build.CN01.AR01", + "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", + "Attributes": [ + { + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN01 Restrict Allowed Build Agents", + "SubSection": "", + "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", "AC-6" ] } @@ -4272,92 +5432,31 @@ } ], "Checks": [ - "organizations_scp_check_deny_regions", - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "vpc_endpoint_connections_trust_boundaries" + "codebuild_project_uses_allowed_github_organizations", + "codebuild_project_user_controlled_buildspec", + "codebuild_project_no_secrets_in_variables" ] }, { - "Id": "CCC.Core.CN08.AR01", - "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Id": "CCC.Build.CN02.AR01", + "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN02 Restrict Allowed External Services for Build Triggers", "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-2", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_cross_region_replication", - "cloudtrail_multi_region_enabled", - "backup_plans_exist", - "backup_vaults_exist", - "backup_vaults_encrypted", - "dynamodb_table_protected_by_backup_plan", - "rds_cluster_protected_by_backup_plan", - "rds_instance_protected_by_backup_plan" - ] - }, - { - "Id": "CCC.Core.CN08.AR02", - "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", - "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH01" ] } ], @@ -4365,41 +5464,165 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" + "PR.AC-4" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "CP-2", - "CP-10" + "AC-3", + "AC-6" ] } ] } ], "Checks": [ - "s3_bucket_cross_region_replication" + "codebuild_project_uses_allowed_github_organizations", + "codebuild_project_source_repo_url_no_sensitive_credentials" ] }, { - "Id": "CCC.Core.CN09.AR01", - "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", + "Id": "CCC.Build.CN03.AR01", + "Description": "Attempt to access the build environment from an external network and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN03 Deny External Network Access for Build Environments", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02", + "CCC.Core.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-5" + ] + } + ] + } + ], + "Checks": [ + "codebuild_project_not_publicly_accessible" + ] + }, + { + "Id": "CCC.CntrReg.CN01.AR01", + "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", + "Attributes": [ + { + "FamilyName": "Risk Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.CntrReg.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "RA-5", + "SI-5" + ] + } + ] + } + ], + "Checks": [ + "ecr_registry_scan_images_on_push_enabled", + "ecr_repositories_scan_vulnerabilities_in_latest_image" + ] + }, + { + "Id": "CCC.CntrReg.CN02.AR01", + "Description": "Confirm that artifacts older than the specified retention period are automatically deleted from the registry.", + "Attributes": [ + { + "FamilyName": "Data Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN02 Implement Cleanup Policies for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that unused or outdated artifacts are cleaned up according to defined policies to manage storage effectively and reduce security risks associated with outdated versions.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH14" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN01.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials or generating temporary session tokens.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", + "SubSection": "", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", "Applicability": [ "tlp-clear", "tlp-green", @@ -4411,9 +5634,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH03" ] } ], @@ -4421,61 +5642,52 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "cloudtrail_bucket_requires_mfa_delete", - "cloudtrail_log_file_validation_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_multi_region_enabled", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled" + "iam_no_root_access_key", + "iam_user_no_setup_initial_access_key", + "iam_user_two_active_access_key", + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges" ] }, { - "Id": "CCC.Core.CN09.AR02", - "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Id": "CCC.IAM.CN01.AR02", + "Description": "When a non-administrative principal attempts to create new credentials or a temporary session token, the service MUST deny the action.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", "Applicability": [ "tlp-clear", "tlp-green", "tlp-amber", "tlp-red" ], - "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH03" ] } ], @@ -4483,63 +5695,52 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "cloudtrail_kms_encryption_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "cloudtrail_log_file_validation_enabled", - "vpc_flow_logs_enabled", - "apigateway_restapi_logging_enabled", - "apigatewayv2_api_access_logging_enabled", - "cloudwatch_log_group_not_publicly_accessible", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled" + "iam_no_root_access_key", + "iam_user_no_setup_initial_access_key", + "iam_user_two_active_access_key", + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges" ] }, { - "Id": "CCC.Core.CN09.AR03", - "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Id": "CCC.IAM.CN02.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating, updating, or attaching policies.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", "Applicability": [ + "tlp-clear", + "tlp-green", "tlp-amber", "tlp-red" ], - "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH06" ] } ], @@ -4547,55 +5748,91 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "cloudtrail_insights_exist", - "cloudtrail_logs_s3_bucket_access_logging_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_log_file_validation_enabled", - "cloudwatch_log_group_kms_encryption_enabled", - "cloudwatch_log_group_not_publicly_accessible", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_changes_to_network_acls_alarm_configured", - "cloudwatch_changes_to_network_gateways_alarm_configured", - "cloudwatch_changes_to_network_route_tables_alarm_configured", - "cloudwatch_changes_to_vpcs_alarm_configured", - "s3_bucket_server_access_logging_enabled" + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_customer_unattached_policy_no_administrative_privileges", + "iam_policy_allows_privilege_escalation", + "iam_inline_policy_allows_privilege_escalation" ] }, { - "Id": "CCC.Core.CN10.AR01", - "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", + "Id": "CCC.IAM.CN02.AR02", + "Description": "When a non-administrative principal attempts to create, update, or attach policies, the service MUST deny the action.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", "SubSection": "", - "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-5", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_customer_unattached_policy_no_administrative_privileges", + "iam_policy_allows_privilege_escalation", + "iam_inline_policy_allows_privilege_escalation" + ] + }, + { + "Id": "CCC.IAM.CN03.AR01", + "Description": "When a policy is created or updated that grants a principal permission to assume a role or impersonate a service identity, the principal MUST NOT contain a wildcard or be public/anonymous.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", + "SubSection": "", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", "Applicability": [ "tlp-green", "tlp-amber", @@ -4606,7 +5843,1511 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH04" + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_cross_account_readonlyaccess_policy", + "iam_role_cross_service_confused_deputy_prevention", + "iam_no_custom_policy_permissive_role_assumption" + ] + }, + { + "Id": "CCC.IAM.CN03.AR02", + "Description": "When an external or unauthenticated principal tries to assume a role or impersonate a service identity, the service MUST deny the action.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", + "SubSection": "", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_cross_account_readonlyaccess_policy", + "iam_role_cross_service_confused_deputy_prevention", + "iam_no_custom_policy_permissive_role_assumption" + ] + }, + { + "Id": "CCC.IAM.CN04.AR01", + "Description": "When an IAM policy is created or updated, it MUST NOT contain allow statements with wildcard permissions, unless the statement is restricted by a condition.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN04 Restrict Wildcard Usage in IAM Policies", + "SubSection": "", + "SubSectionObjective": "Limit the use of wildcard permissions in IAM policies to prevent overly broad access from being granted by default.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_customer_unattached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges", + "iam_policy_no_full_access_to_kms", + "iam_policy_no_full_access_to_cloudtrail", + "iam_inline_policy_no_full_access_to_kms", + "iam_inline_policy_no_full_access_to_cloudtrail" + ] + }, + { + "Id": "CCC.IAM.CN05.AR01", + "Description": "When a new cloud account is provisioned, a password policy MUST be configured for IAM users following the minimum PCI DSS v4.0.1 configurations.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN05 Strong Password Policies for IAM Users", + "SubSection": "", + "SubSectionObjective": "Ensure that the password policies for IAM users have strong configurations.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a new cloud account is provisioned, a password policy must be configured for all IAM users to align with the minimum requirements defined in PCI DSS v4.0.1. This includes, at a minimum: strength: 0 # Not yet specified - reference-id: A password length of at least 12 characters. strength: 0 # Not yet specified - reference-id: A mix of upper- and lower-case letters, numbers, and special characters. strength: 0 # Not yet specified - reference-id: Prevention of the use of previously used passwords (password history). strength: 0 # Not yet specified - reference-id: Password expiration at a defined interval (e.g., every 90 days). strength: 0 # Not yet specified - reference-id: Account lockout after a defined number of failed login attempts.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-5" + ] + }, + { + "ReferenceId": "PCI-DSS", + "Identifiers": [ + "8.3.9", + "8.6.3" + ] + } + ] + } + ], + "Checks": [ + "iam_password_policy_minimum_length_14", + "iam_password_policy_uppercase", + "iam_password_policy_lowercase", + "iam_password_policy_symbol", + "iam_password_policy_number", + "iam_password_policy_expires_passwords_within_90_days_or_less", + "iam_password_policy_reuse_24" + ] + }, + { + "Id": "CCC.IAM.CN06.AR01", + "Description": "When a static credential such as an access key has existed for 90 days or more, it MUST be rotated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN06 Maximum Age for Long-Term Static Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that long-lived static credentials like access keys are programmatically rotated within a defined time period to limit the window of opportunity if compromised.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a static credential such as an access key has existed for 90 days or more, it must be automatically rotated to reduce the risk of compromise due to long-term exposure. Organizations should implement automated checks to identify aging credentials and enforce rotation policies. Additionally, access key usage should be regularly monitored, and credentials that are no longer in use should be deactivated or deleted promptly. Where possible, prefer temporary, short-lived credentials over long-lived static ones to further minimize risk.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH09", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_rotate_access_key_90_days" + ] + }, + { + "Id": "CCC.IAM.CN07.AR01", + "Description": "When a user account is disabled or deleted in the organization's IdP, the corresponding cloud identity and its access policies MUST be disabled or deleted within 24 hours.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN07 Automate Identity De-provisioning", + "SubSection": "", + "SubSectionObjective": "Ensure that when an identity is terminated in the central Identity Provider (IdP), ts corresponding access to cloud resources is revoked automatically.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH10", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_user_console_access_unused", + "iam_user_accesskey_unused" + ] + }, + { + "Id": "CCC.IAM.CN08.AR01", + "Description": "When an IAM user has credentials, such as passwords or access keys, that have not been used for 90 days or more, the unused credentials MUST be removed or deactivated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN08 Maximum Age for Unused Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that unused IAM credentals are removed to reduce exposure in the event of potential compromise.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "IAM user credentials (such as passwords or access keys) that have not been used for 90 days or more must be automatically removed or deactivated.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH11", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_user_accesskey_unused", + "iam_user_console_access_unused" + ] + }, + { + "Id": "CCC.IAM.CN09.AR01", + "Description": "When a human user accesses the cloud environment, they MUST authenticate through the organization's federated IdP via a standard protocol (e.g., SAML, OIDC).", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN09 Enforce Federated Single Sign-On (SSO) for Human Users", + "SubSection": "", + "SubSectionObjective": "Ensure that all human users must authenticate through a central, federated Identity Provider (IdP) to access the cloud environment. This eliminates cloud-native user accounts with long-lived passwords, centralizes authentication controls, and simplifies lifecycle management.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-2" + ] + } + ] + } + ], + "Checks": [ + "iam_check_saml_providers_sts" + ] + }, + { + "Id": "CCC.IAM.CN10.AR01", + "Description": "When suspicious API requests are detected, real time alerts MUST be generated to notify security personnel.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "cloudwatch_log_metric_filter_authentication_failures", + "cloudwatch_log_metric_filter_unauthorized_api_calls", + "cloudwatch_log_metric_filter_root_usage", + "cloudwatch_log_metric_filter_sign_in_without_mfa", + "guardduty_is_enabled" + ] + }, + { + "Id": "CCC.IAM.CN10.AR02", + "Description": "When suspicious API requests are detected, the associated events MUST be logged, including the source details, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_multi_region_enabled_logging_management_events", + "cloudwatch_log_metric_filter_authentication_failures", + "cloudwatch_log_metric_filter_unauthorized_api_calls" + ] + }, + { + "Id": "CCC.IAM.CN11.AR01", + "Description": "When a cloud account or organization is provisioned, the native automated access and usage analysis services MUST be enabled to continuously monitor for external or public access to resources, and unused access.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN11 Enable Continuous IAM Access and Usage Analysis", + "SubSection": "", + "SubSectionObjective": "Enable and configure the cloud provider's native access and usage analysis services to continuously monitor for external access paths and internal unused access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02", + "CCC.IAM.TH10", + "CCC.IAM.TH11" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-01", + "ID.IM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "CA-7", + "RA-5" + ] + } + ] + } + ], + "Checks": [ + "accessanalyzer_enabled", + "accessanalyzer_enabled_without_findings" + ] + }, + { + "Id": "CCC.GenAI.CN01.AR01", + "Description": "Untrusted input such as user queries, RAG data or tool output MUST be validated before it is passed to a GenAI model.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_prompt_attack_filter_enabled", + "bedrock_guardrail_sensitive_information_filter_enabled", + "bedrock_agent_guardrail_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN01.AR02", + "Description": "If malicious patterns such as prompt injection or sensitive data are detected during input validation, the input MUST be blocked or sanitised.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_prompt_attack_filter_enabled", + "bedrock_guardrail_sensitive_information_filter_enabled", + "bedrock_agent_guardrail_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN02.AR01", + "Description": "GenAI model output MUST be validated for format conformance, malicious patterns, sensitive data and inapropriate content before being passed to users, application or plugins.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_sensitive_information_filter_enabled", + "bedrock_agent_guardrail_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN02.AR02", + "Description": "In the event of policy violations, the AI-generated content MUST be redacted, encoded or rejected.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_sensitive_information_filter_enabled", + "bedrock_agent_guardrail_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN03.AR01", + "Description": "When data is designated for model training or RAG ingestion, then its source MUST be explicitly approved and its provenance documented.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN03.AR02", + "Description": "Data from unvetted sources MUST NOT be used in production systems.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN04.AR01", + "Description": "When data is ingested for training, fine-tuning or conversion to vector embeddings, it MUST be validated for sensitive information or malicious content.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_sensitive_information_filter_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN04.AR02", + "Description": "If sensitive data or malicious content is detected, it must be rejected, redacted or flagged for manual review.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [ + "bedrock_guardrail_sensitive_information_filter_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN05.AR01", + "Description": "When a RAG-enabled system generates a response containing information retrieved from its knowledge base, then the response MUST include a verifiable citation that links back to the specific source document.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN05 Citations and Source Traceability", + "SubSection": "", + "SubSectionObjective": "Require the GenAI system to provide citations or direct links back to the source documents used to generate a response, in to enhance the transparency, trustworthiness, and verifiability of AI-generated content.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH09", + "CCC.GenAI.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-DET-013" + ] + } + ] + } + ], + "Checks": [ + "bedrock_model_invocation_logging_enabled", + "bedrock_model_invocation_logs_encryption_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN06.AR01", + "Description": "When an LLM invokes an external tool (e.g., an API, a plugin), then the tool MUST operate with the least privileges required for performing its intended functionality.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.GenAI.CN06 Least Privilege for Plugins", + "SubSection": "", + "SubSectionObjective": "Restricts the permissions of any external tools the GenAI system can call to limit the potential damage if an agent is coerced to perform unintended actions or vulnerabilities in the tools are exploited.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH07", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Agent Permissions" + ] + } + ] + } + ], + "Checks": [ + "bedrock_api_key_no_administrative_privileges", + "bedrock_api_key_no_long_term_credentials" + ] + }, + { + "Id": "CCC.GenAI.CN07.AR01", + "Description": "When an application makes an API call to a foundational model in a production environment, then it MUST specify an explicit version identifier.", + "Attributes": [ + { + "FamilyName": "Configuration Management", + "FamilyDescription": "The Configuration Management control family involves establishing, maintaining and monitoring the configuration of the service and related applications and infrastructure to ensure consistency, secure defaults and compliance.", + "Section": "CCC.GenAI.CN07 Model Version Pinning", + "SubSection": "", + "SubSectionObjective": "Mandate that applications are locked (\"pinned\") to a specific, tested version of a foundational model to prevent unexpected behaviour changes introduced by provider-side updates.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-010" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR01", + "Description": "When a new AI model is considered for production deployment, it MUST undergo a formal red teaming and quality assurance review.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR02", + "Description": "If model quality review or red teaming identifies an issue that exceeds the organization's risk tolerance, the model MUST NOT be deployed until the issue is remediated.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN01.AR01", + "Description": "Verify that only authorized users can access MLDE resources, and that access modes are properly defined and enforced.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN01 Define Access Mode for ML Development Environments", + "SubSection": "", + "SubSectionObjective": "Ensure that access to Machine Learning Development Environment (MLDE) resources is strictly defined and controlled. Only authorized users with appropriate permissions can access these environments, mitigating the risk of unauthorized access, data leakage, or service disruption.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.1", + "2013 A.9.2.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-02" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_root_access_disabled", + "sagemaker_notebook_instance_vpc_settings_configured" + ] + }, + { + "Id": "CCC.MLDE.CN03.AR01", + "Description": "Verify that root access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_root_access_disabled" + ] + }, + { + "Id": "CCC.MLDE.CN03.AR02", + "Description": "For MLDE instances without sensitive data, ensure that root access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_root_access_disabled" + ] + }, + { + "Id": "CCC.MLDE.CN04.AR01", + "Description": "Verify that terminal access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_root_access_disabled" + ] + }, + { + "Id": "CCC.MLDE.CN04.AR02", + "Description": "For MLDE instances without sensitive data, ensure that terminal access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_root_access_disabled" + ] + }, + { + "Id": "CCC.MLDE.CN02.AR01", + "Description": "Confirm that file download functionality is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.Core.TH02" ] } ], @@ -4620,166 +7361,98 @@ { "ReferenceId": "CCM", "Identifiers": [ - "DSP-10", - "DSP-19" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-4" - ] - } - ] - } - ], - "Checks": [ - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "vpc_endpoint_connections_trust_boundaries", - "s3_bucket_cross_account_access" - ] - }, - { - "Id": "CCC.Core.CN02.AR01", - "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN02 Encrypt Data for Storage", - "SubSection": "", - "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "UEM-08", - "DSP-17" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-13", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "s3_bucket_default_encryption", - "s3_bucket_kms_encryption", - "firehose_stream_encrypted_at_rest", - "backup_vaults_encrypted", - "backup_recovery_point_encrypted", - "cloudtrail_kms_encryption_enabled", - "cloudwatch_log_group_kms_encryption_enabled", - "opensearch_service_domains_encryption_at_rest_enabled", - "opensearch_service_domains_node_to_node_encryption_enabled", - "kafka_cluster_encryption_at_rest_uses_cmk", - "kinesis_stream_encrypted_at_rest", - "dynamodb_tables_kms_cmk_encryption_enabled", - "dynamodb_accelerator_cluster_encryption_enabled", - "ec2_ebs_default_encryption", - "ec2_ebs_volume_encryption", - "storagegateway_fileshare_encryption_enabled" - ] - }, - { - "Id": "CCC.Core.CN11.AR01", - "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "DSI-05", + "DSI-07" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.13.2.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "SC-7", + "SC-8" ] } ] } ], - "Checks": [ - "kms_cmk_rotation_enabled", - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_not_multi_region", - "kms_cmk_are_used" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR02", - "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Id": "CCC.MLDE.CN02.AR02", + "Description": "For MLDE instances without sensitive data, ensure that file downloads are monitored and logged.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSI-05", + "DSI-07" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.2.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-8" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN05.AR01", + "Description": "Verify that only approved VM and container images can be selected when creating MLDE instances.", + "Attributes": [ + { + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", + "Applicability": [ + "tlp-red", "tlp-amber" ], "Recommendation": "", @@ -4787,7 +7460,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4795,52 +7468,43 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "kms_cmk_rotation_enabled", - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_not_multi_region", - "kms_cmk_are_used" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR03", - "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Id": "CCC.MLDE.CN05.AR02", + "Description": "Attempt to create an MLDE instance with an unapproved image and confirm that it is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "", - "SubSection": "CCC.Core.CN11 Protect Encryption Keys", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", "Applicability": [ - "tlp-amber", "tlp-red" ], "Recommendation": "", @@ -4848,7 +7512,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4856,62 +7520,109 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_rotation_enabled", - "kms_cmk_not_multi_region", - "kms_cmk_are_used" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR04", - "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Id": "CCC.MLDE.CN06.AR01", + "Description": "Verify that automatic scheduled upgrades are enabled on user-managed MLDE instances containing sensitive data.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", "Applicability": [ - "tlp-clear", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH04", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-12" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-01", + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.6.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN06.AR02", + "Description": "Ensure that the upgrade schedule is appropriately configured and does not interfere with critical operations.", + "Attributes": [ + { + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", + "Applicability": [ + "tlp-red", + "tlp-amber", "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-clear" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04", + "CCC.Core.TH06" ] } ], @@ -4919,109 +7630,43 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-12" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-01", + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.6.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "SI-2" ] } ] } ], - "Checks": [ - "kms_cmk_rotation_enabled", - "kms_cmk_not_deleted_unintentionally", - "kms_cmk_not_multi_region", - "kms_cmk_are_used" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR05", - "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Id": "CCC.MLDE.CN07.AR01", + "Description": "Verify that MLDE instances containing sensitive data cannot be accessed via public IP addresses.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-clear", - "tlp-green" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "kms_cmk_rotation_enabled", - "kms_cmk_not_multi_region" - ] - }, - { - "Id": "CCC.Core.CN11.AR06", - "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", "Applicability": [ "tlp-red" ], @@ -5030,444 +7675,8 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "kms_cmk_rotation_enabled" - ] - }, - { - "Id": "CCC.Core.CN14.AR01", - "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "neptune_cluster_backup_enabled" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber" - ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "backup_vaults_exist", - "backup_plans_exist", - "backup_reportplans_exist", - "backup_vaults_encrypted", - "backup_recovery_point_encrypted", - "neptune_cluster_backup_enabled", - "rds_instance_backup_enabled", - "rds_instance_protected_by_backup_plan", - "rds_cluster_protected_by_backup_plan", - "dynamodb_table_protected_by_backup_plan" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "backup_vaults_exist", - "backup_vaults_encrypted", - "backup_plans_exist", - "backup_reportplans_exist", - "backup_recovery_point_encrypted", - "neptune_cluster_backup_enabled" - ] - }, - { - "Id": "CCC.Core.CN03.AR01", - "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_user_mfa_enabled_console_access", - "iam_administrator_access_with_mfa", - "cognito_user_pool_mfa_enabled" - ] - }, - { - "Id": "CCC.Core.CN03.AR02", - "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_user_mfa_enabled_console_access", - "iam_administrator_access_with_mfa", - "cognito_user_pool_mfa_enabled" - ] - }, - { - "Id": "CCC.Core.CN03.AR03", - "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "cognito_user_pool_mfa_enabled", - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_user_mfa_enabled_console_access", - "iam_user_hardware_mfa_enabled", - "iam_administrator_access_with_mfa" - ] - }, - { - "Id": "CCC.Core.CN03.AR04", - "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "iam_user_mfa_enabled_console_access", - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_user_hardware_mfa_enabled", - "iam_administrator_access_with_mfa", - "apigateway_restapi_authorizers_enabled", - "apigateway_restapi_public_with_authorizer" - ] - }, - { - "Id": "CCC.Core.CN05.AR01", - "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" + "CCC.MLDE.TH02", + "CCC.VPC.TH02" ] } ], @@ -5481,75 +7690,317 @@ { "ReferenceId": "CCM", "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" + "SEF-05" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.13.1.3" + "2013 A.13.1.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3" + "SC-7" ] } ] } ], "Checks": [ - "apigateway_restapi_authorizers_enabled", - "apigateway_restapi_public", - "apigateway_restapi_public_with_authorizer", - "apigatewayv2_api_authorizers_enabled", - "awslambda_function_url_public", + "sagemaker_notebook_instance_without_direct_internet_access_configured" + ] + }, + { + "Id": "CCC.MLDE.CN07.AR02", + "Description": "For MLDE instances without sensitive data requiring public access, ensure that appropriate security controls are in place and access is approved.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_without_direct_internet_access_configured" + ] + }, + { + "Id": "CCC.MLDE.CN08.AR01", + "Description": "Verify that MLDE instances containing sensitive data can only be deployed in approved virtual networks with appropriate security controls.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_vpc_settings_configured", + "sagemaker_models_vpc_settings_configured", + "sagemaker_training_jobs_vpc_settings_configured" + ] + }, + { + "Id": "CCC.MLDE.CN08.AR02", + "Description": "Ensure that MLDE instances without sensitive data are deployed in networks that meet organizational security standards.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "sagemaker_notebook_instance_vpc_settings_configured", + "sagemaker_models_vpc_settings_configured", + "sagemaker_training_jobs_vpc_settings_configured" + ] + }, + { + "Id": "CCC.Message.CN01.AR01", + "Description": "Attempt to publish a message without using a customer-managed encryption key and verify that the message is rejected or not stored.", + "Attributes": [ + { + "FamilyName": "Encryption", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Message.CN01 Use Customer-Managed Encryption Keys (CMEK) for Messages", + "SubSection": "", + "SubSectionObjective": "Ensure that messages are encrypted using customer-managed encryption keys (CMEK) to provide enhanced control over encryption processes and keys, meeting compliance and security requirements.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-12", + "SC-13" + ] + } + ] + } + ], + "Checks": [ + "sns_topics_kms_encryption_at_rest_enabled", + "sqs_queues_server_side_encryption_enabled", + "kafka_cluster_encryption_at_rest_uses_cmk" + ] + }, + { + "Id": "CCC.SvlsComp.CN01.AR01", + "Description": "Attempt to access the serverless function over the public internet and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN01 Enforce Use of Private Endpoints for Serverless Function", + "SubSection": "", + "SubSectionObjective": "Ensure that the serverless function is accessible only through a private endpoint, allowing it to communicate securely within a virtual private network and preventing unauthorized external access.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-8" + ] + } + ] + } + ], + "Checks": [ + "awslambda_function_inside_vpc", "awslambda_function_not_publicly_accessible", - "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", - "s3_bucket_public_access", - "s3_bucket_public_list_acl", - "s3_bucket_public_write_acl", - "s3_bucket_cross_account_access", - "s3_account_level_public_access_blocks", - "iam_policy_no_full_access_to_cloudtrail", - "iam_policy_no_full_access_to_kms", - "iam_inline_policy_no_full_access_to_cloudtrail", - "iam_inline_policy_no_full_access_to_kms", - "iam_role_administratoraccess_policy", - "iam_group_administrator_access_policy", - "iam_user_administrator_access_policy", - "iam_policy_attached_only_to_group_or_roles", - "iam_role_cross_account_readonlyaccess_policy", - "iam_role_cross_service_confused_deputy_prevention" + "awslambda_function_url_public" ] }, { - "Id": "CCC.Core.CN05.AR02", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Id": "CCC.SvlsComp.CN02.AR01", + "Description": "Send requests to invoke the function up to the allowed threshold and confirm they are successful; then send additional requests exceeding the threshold from the same entity and verify that they are denied.", "Attributes": [ { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "FamilyName": "Availability", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN02 Implement Function Invocation Rate Limits", "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "SubSectionObjective": "Ensure that function invocation is limited to a specified threshold from any single entity, preventing resource exhaustion and denial of service attacks.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH12" ] } ], @@ -5557,650 +8008,19 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" + "PR.DS-4" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3" + "SC-5" ] } ] } ], - "Checks": [ - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_avoid_root_usage", - "iam_user_mfa_enabled_console_access", - "iam_administrator_access_with_mfa", - "iam_group_administrator_access_policy", - "iam_role_administratoraccess_policy", - "iam_inline_policy_no_full_access_to_cloudtrail", - "iam_inline_policy_no_full_access_to_kms", - "iam_policy_no_full_access_to_cloudtrail", - "iam_policy_no_full_access_to_kms", - "iam_policy_allows_privilege_escalation", - "iam_inline_policy_allows_privilege_escalation", - "iam_customer_attached_policy_no_administrative_privileges", - "iam_customer_unattached_policy_no_administrative_privileges", - "iam_aws_attached_policy_no_administrative_privileges", - "iam_password_policy_minimum_length_14", - "iam_password_policy_uppercase", - "iam_password_policy_lowercase", - "iam_password_policy_symbol", - "iam_password_policy_number", - "iam_password_policy_expires_passwords_within_90_days_or_less", - "iam_password_policy_reuse_24", - "iam_check_saml_providers_sts", - "iam_policy_attached_only_to_group_or_roles" - ] - }, - { - "Id": "CCC.Core.CN05.AR03", - "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "vpc_endpoint_connections_trust_boundaries", - "iam_role_cross_service_confused_deputy_prevention", - "iam_role_cross_account_readonlyaccess_policy", - "s3_bucket_cross_account_access", - "eventbridge_bus_cross_account_access", - "eventbridge_schema_registry_cross_account_access" - ] - }, - { - "Id": "CCC.Core.CN05.AR04", - "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "", - "SubSection": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "accessanalyzer_enabled", - "accessanalyzer_enabled_without_findings", - "vpc_endpoint_connections_trust_boundaries", - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "s3_bucket_cross_account_access", - "s3_bucket_public_access", - "iam_administrator_access_with_mfa", - "iam_group_administrator_access_policy", - "iam_user_administrator_access_policy", - "iam_inline_policy_allows_privilege_escalation", - "iam_inline_policy_no_full_access_to_kms", - "iam_inline_policy_no_full_access_to_cloudtrail", - "iam_policy_no_full_access_to_kms", - "iam_policy_no_full_access_to_cloudtrail", - "iam_policy_attached_only_to_group_or_roles", - "iam_user_mfa_enabled_console_access" - ] - }, - { - "Id": "CCC.Core.CN05.AR05", - "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "awslambda_function_url_public", - "apigateway_restapi_public", - "apigateway_restapi_public_with_authorizer", - "s3_bucket_public_list_acl", - "s3_bucket_public_write_acl", - "s3_bucket_public_access", - "s3_bucket_policy_public_write_access", - "sns_topics_not_publicly_accessible", - "ec2_securitygroup_allow_ingress_from_internet_to_all_ports", - "ec2_networkacl_allow_ingress_any_port", - "ec2_networkacl_allow_ingress_tcp_port_22", - "ec2_networkacl_allow_ingress_tcp_port_3389", - "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", - "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", - "ec2_securitygroup_default_restrict_traffic", - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "vpc_endpoint_connections_trust_boundaries", - "vpc_endpoint_for_ec2_enabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR06", - "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "vpc_endpoint_connections_trust_boundaries", - "vpc_endpoint_services_allowed_principals_trust_boundaries", - "iam_role_cross_service_confused_deputy_prevention", - "iam_role_cross_account_readonlyaccess_policy", - "iam_policy_attached_only_to_group_or_roles", - "iam_group_administrator_access_policy", - "iam_user_mfa_enabled_console_access", - "iam_root_mfa_enabled", - "iam_root_hardware_mfa_enabled", - "iam_no_root_access_key", - "iam_administrator_access_with_mfa", - "iam_root_credentials_management_enabled", - "iam_check_saml_providers_sts", - "iam_user_hardware_mfa_enabled" - ] - }, - { - "Id": "CCC.Core.CN04.AR01", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_multi_region_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_log_file_validation_enabled", - "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled", - "cloudwatch_log_metric_filter_authentication_failures", - "cloudwatch_log_metric_filter_unauthorized_api_calls", - "cloudwatch_log_metric_filter_root_usage", - "cloudwatch_log_metric_filter_sign_in_without_mfa", - "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", - "cloudwatch_log_metric_filter_policy_changes", - "cloudwatch_log_metric_filter_security_group_changes", - "cloudwatch_log_metric_filter_disable_or_scheduled_deletion_of_kms_cmk", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", - "cloudwatch_changes_to_network_acls_alarm_configured", - "cloudwatch_changes_to_network_gateways_alarm_configured", - "cloudwatch_changes_to_network_route_tables_alarm_configured", - "cloudwatch_changes_to_vpcs_alarm_configured", - "vpc_flow_logs_enabled", - "apigateway_restapi_logging_enabled", - "apigatewayv2_api_access_logging_enabled" - ] - }, - { - "Id": "CCC.Core.CN04.AR02", - "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled", - "cloudtrail_multi_region_enabled_logging_management_events", - "cloudtrail_cloudwatch_logging_enabled", - "vpc_flow_logs_enabled", - "apigateway_restapi_logging_enabled", - "apigatewayv2_api_access_logging_enabled", - "cloudtrail_threat_detection_enumeration", - "cloudtrail_threat_detection_privilege_escalation", - "cloudtrail_threat_detection_llm_jacking" - ] - }, - { - "Id": "CCC.Core.CN04.AR03", - "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_insights_exist", - "cloudtrail_multi_region_enabled", - "cloudtrail_cloudwatch_logging_enabled", - "cloudtrail_kms_encryption_enabled", - "cloudtrail_log_file_validation_enabled", - "cloudtrail_logs_s3_bucket_is_not_publicly_accessible", - "cloudtrail_s3_dataevents_read_enabled", - "cloudtrail_s3_dataevents_write_enabled", - "cloudwatch_log_group_kms_encryption_enabled", - "cloudwatch_log_group_not_publicly_accessible", - "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", - "cloudwatch_log_metric_filter_authentication_failures", - "apigateway_restapi_logging_enabled", - "apigatewayv2_api_access_logging_enabled", - "vpc_flow_logs_enabled" - ] - }, - { - "Id": "CCC.Core.CN07.AR01", - "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_threat_detection_enumeration" - ] - }, - { - "Id": "CCC.Core.CN07.AR02", - "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "cloudtrail_threat_detection_enumeration" - ] + "Checks": [] } ] } diff --git a/prowler/compliance/azure/ccc_azure.json b/prowler/compliance/azure/ccc_azure.json index 004137ad53..cb87346d13 100644 --- a/prowler/compliance/azure/ccc_azure.json +++ b/prowler/compliance/azure/ccc_azure.json @@ -1,10 +1,1698 @@ { "Framework": "CCC", - "Version": "", + "Version": "v2025.10", "Provider": "Azure", "Name": "Common Cloud Controls Catalog (CCC)", "Description": "Common Cloud Controls Catalog (CCC) for Azure", "Requirements": [ + { + "Id": "CCC.Core.CN01.AR01", + "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "storage_secure_transfer_required_is_enabled", + "storage_ensure_minimum_tls_version_12", + "storage_smb_channel_encryption_with_secure_algorithm", + "storage_smb_protocol_version_is_latest", + "postgresql_flexible_server_enforce_ssl_enabled", + "mysql_flexible_server_ssl_connection_enabled", + "mysql_flexible_server_minimum_tls_version_12", + "sqlserver_recommended_minimal_tls_version", + "app_minimum_tls_version_12", + "app_ensure_http_is_redirected_to_https", + "app_ensure_using_http20", + "app_ftp_deployment_disabled", + "app_function_ftps_deployment_disabled" + ] + }, + { + "Id": "CCC.Core.CN01.AR02", + "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "network_ssh_internet_access_restricted", + "vm_linux_enforce_ssh_authentication" + ] + }, + { + "Id": "CCC.Core.CN01.AR03", + "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "app_ensure_http_is_redirected_to_https", + "storage_secure_transfer_required_is_enabled", + "app_ftp_deployment_disabled", + "app_function_ftps_deployment_disabled" + ] + }, + { + "Id": "CCC.Core.CN01.AR07", + "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN01.AR08", + "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "app_client_certificates_on" + ] + }, + { + "Id": "CCC.Core.CN13.AR01", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "keyvault_key_expiration_set_in_non_rbac", + "keyvault_rbac_key_expiration_set", + "keyvault_non_rbac_secret_expiration_set", + "keyvault_rbac_secret_expiration_set" + ] + }, + { + "Id": "CCC.Core.CN13.AR02", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN13.AR03", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN06.AR01", + "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN06.AR02", + "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN08.AR01", + "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [ + "storage_geo_redundant_enabled", + "vm_backup_enabled" + ] + }, + { + "Id": "CCC.Core.CN08.AR02", + "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [ + "storage_geo_redundant_enabled" + ] + }, + { + "Id": "CCC.Core.CN09.AR01", + "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "monitor_storage_account_with_activity_logs_is_private", + "monitor_storage_account_with_activity_logs_cmk_encrypted" + ] + }, + { + "Id": "CCC.Core.CN09.AR02", + "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories" + ] + }, + { + "Id": "CCC.Core.CN09.AR03", + "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists" + ] + }, + { + "Id": "CCC.Core.CN10.AR01", + "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-10", + "DSP-19" + ] + } + ] + } + ], + "Checks": [ + "storage_cross_tenant_replication_disabled" + ] + }, + { + "Id": "CCC.Core.CN02.AR01", + "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN02 Encrypt Data for Storage", + "SubSection": "", + "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "UEM-08", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_infrastructure_encryption_is_enabled", + "storage_ensure_encryption_with_customer_managed_keys", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk", + "sqlserver_tde_encryption_enabled", + "sqlserver_tde_encrypted_with_cmk", + "databricks_workspace_cmk_encryption_enabled", + "monitor_storage_account_with_activity_logs_cmk_encrypted" + ] + }, + { + "Id": "CCC.Core.CN11.AR01", + "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "storage_smb_channel_encryption_with_secure_algorithm" + ] + }, + { + "Id": "CCC.Core.CN11.AR02", + "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR03", + "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "vm_ensure_attached_disks_encrypted_with_cmk", + "vm_ensure_unattached_disks_encrypted_with_cmk", + "sqlserver_tde_encrypted_with_cmk", + "databricks_workspace_cmk_encryption_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR04", + "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "keyvault_rbac_enabled", + "keyvault_private_endpoints", + "keyvault_access_only_through_private_endpoints", + "keyvault_logging_enabled", + "keyvault_recoverable" + ] + }, + { + "Id": "CCC.Core.CN11.AR05", + "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR06", + "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "storage_key_rotation_90_days", + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN14.AR01", + "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "CCC.Core.CN14.AR02", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "CCC.Core.CN14.AR03", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "CCC.Core.CN03.AR01", + "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "entra_privileged_user_has_mfa", + "entra_non_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa", + "entra_security_defaults_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR02", + "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api", + "app_function_access_keys_configured", + "app_function_identity_is_configured" + ] + }, + { + "Id": "CCC.Core.CN03.AR03", + "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "entra_privileged_user_has_mfa", + "entra_non_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa", + "entra_security_defaults_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR04", + "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api", + "app_function_access_keys_configured" + ] + }, + { + "Id": "CCC.Core.CN05.AR01", + "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "aks_cluster_rbac_enabled", + "aks_clusters_public_access_disabled", + "app_ensure_auth_is_set_up", + "app_register_with_identity", + "app_function_identity_is_configured", + "app_function_identity_without_admin_privileges", + "app_function_not_publicly_accessible", + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "keyvault_rbac_enabled", + "keyvault_private_endpoints", + "keyvault_access_only_through_private_endpoints", + "entra_global_admin_in_less_than_five_users", + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "vm_jit_access_enabled" + ] + }, + { + "Id": "CCC.Core.CN05.AR02", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "entra_global_admin_in_less_than_five_users", + "entra_privileged_user_has_mfa", + "entra_non_privileged_user_has_mfa", + "entra_conditional_access_policy_require_mfa_for_management_api", + "aks_cluster_rbac_enabled", + "containerregistry_admin_user_disabled", + "keyvault_rbac_enabled" + ] + }, + { + "Id": "CCC.Core.CN05.AR03", + "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_cross_tenant_replication_disabled", + "storage_default_to_entra_authorization_enabled", + "entra_trusted_named_locations_exists" + ] + }, + { + "Id": "CCC.Core.CN05.AR04", + "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_default_network_access_rule_is_denied", + "storage_ensure_private_endpoints_in_storage_accounts", + "storage_account_key_access_disabled", + "storage_default_to_entra_authorization_enabled", + "containerregistry_not_publicly_accessible", + "containerregistry_uses_private_link", + "keyvault_private_endpoints", + "keyvault_access_only_through_private_endpoints", + "cosmosdb_account_use_private_endpoints", + "cosmosdb_account_firewall_use_selected_networks", + "sqlserver_unrestricted_inbound_access", + "network_http_internet_access_restricted" + ] + }, + { + "Id": "CCC.Core.CN05.AR05", + "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "aks_clusters_created_with_private_nodes", + "aks_clusters_public_access_disabled", + "app_function_not_publicly_accessible", + "containerregistry_not_publicly_accessible", + "keyvault_private_endpoints", + "storage_ensure_private_endpoints_in_storage_accounts", + "network_http_internet_access_restricted", + "network_rdp_internet_access_restricted", + "network_ssh_internet_access_restricted" + ] + }, + { + "Id": "CCC.Core.CN05.AR06", + "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "entra_privileged_user_has_mfa", + "entra_non_privileged_user_has_mfa", + "entra_global_admin_in_less_than_five_users", + "entra_conditional_access_policy_require_mfa_for_management_api", + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "keyvault_rbac_enabled", + "vm_jit_access_enabled" + ] + }, + { + "Id": "CCC.Core.CN04.AR01", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories", + "monitor_alert_create_update_nsg", + "monitor_alert_delete_nsg", + "monitor_alert_create_update_public_ip_address_rule", + "monitor_alert_delete_public_ip_address_rule", + "monitor_alert_create_update_security_solution", + "monitor_alert_delete_security_solution", + "monitor_alert_create_policy_assignment", + "monitor_alert_create_update_sqlserver_fr" + ] + }, + { + "Id": "CCC.Core.CN04.AR02", + "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories", + "keyvault_logging_enabled", + "app_http_logs_enabled" + ] + }, + { + "Id": "CCC.Core.CN04.AR03", + "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories", + "keyvault_logging_enabled", + "app_http_logs_enabled" + ] + }, + { + "Id": "CCC.Core.CN07.AR01", + "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN07.AR02", + "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.AuditLog.CN01.AR01", "Description": "When the signature validation process is performed, then it MUST detect any modification of data.", @@ -18,13 +1706,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure hash of data is included in digital signature. ", + "Recommendation": "Ensure hash of data is included in digital signature.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -59,13 +1747,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure verification process includes a chained hash function. ", + "Recommendation": "Ensure verification process includes a chained hash function.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -106,7 +1794,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -130,9 +1818,7 @@ ], "Checks": [ "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" + "monitor_diagnostic_setting_with_appropriate_categories" ] }, { @@ -149,12 +1835,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -175,12 +1861,7 @@ ] } ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "keyvault_logging_enabled", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN03.AR02", @@ -196,12 +1877,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -222,22 +1903,7 @@ ] } ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_alert_service_health_exists", - "monitor_alert_create_update_sqlserver_fr", - "monitor_alert_delete_nsg", - "monitor_alert_delete_public_ip_address_rule", - "monitor_alert_delete_security_solution", - "monitor_alert_create_update_nsg", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_delete_policy_assignment" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN04.AR01", @@ -253,13 +1919,13 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability. ", + "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01", - "CCC.TH09" + "CCC.Core.TH01", + "CCC.Core.TH09" ] } ], @@ -281,11 +1947,7 @@ } ], "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private", - "storage_blob_public_access_level_is_disabled" + "monitor_diagnostic_settings_exists" ] }, { @@ -302,12 +1964,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure audit log exporting. ", + "Recommendation": "Configure audit log exporting.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -331,9 +1993,7 @@ ], "Checks": [ "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" + "monitor_diagnostic_setting_with_appropriate_categories" ] }, { @@ -351,13 +2011,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period. ", + "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -378,10 +2038,7 @@ ] } ], - "Checks": [ - "storage_ensure_soft_delete_is_enabled", - "monitor_diagnostic_settings_exists" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN07.AR01", @@ -398,13 +2055,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket. ", + "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -441,12 +2098,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure object lock policy. ", + "Recommendation": "Configure object lock policy.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -467,12 +2124,7 @@ ] } ], - "Checks": [ - "storage_ensure_soft_delete_is_enabled", - "monitor_diagnostic_settings_exists", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN09.AR01", @@ -488,12 +2140,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Review field level access controls on audit data. ", + "Recommendation": "Review field level access controls on audit data.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -519,9 +2171,7 @@ } ], "Checks": [ - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_diagnostic_settings_exists" + "monitor_storage_account_with_activity_logs_is_private" ] }, { @@ -539,12 +2189,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -568,7 +2218,6 @@ "Checks": [ "storage_blob_public_access_level_is_disabled", "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", "storage_ensure_private_endpoints_in_storage_accounts" ] }, @@ -587,12 +2236,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -616,944 +2265,16 @@ "Checks": [ "storage_blob_public_access_level_is_disabled", "storage_default_network_access_rule_is_denied", - "storage_ensure_private_endpoints_in_storage_accounts", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private" + "storage_ensure_private_endpoints_in_storage_accounts" ] }, - { - "Id": "CCC.Build.CN01.AR01", - "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", - "Attributes": [ - { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN01 Restrict Allowed Build Agents", - "SubSection": "", - "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.Build.CN02.AR01", - "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", - "Attributes": [ - { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN02 Restrict Allowed External Services for Build Triggers", - "SubSection": "", - "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.Build.CN03.AR01", - "Description": "Attempt to access the build environment from an external network and verify that access is denied.", - "Attributes": [ - { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.Build.CN03 Deny External Network Access for Build Environments", - "SubSection": "", - "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02", - "CCC.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-7", - "SC-5" - ] - } - ] - } - ], - "Checks": [ - "aks_clusters_public_access_disabled", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "app_function_not_publicly_accessible", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted" - ] - }, - { - "Id": "CCC.CntrReg.CN01.AR01", - "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", - "Attributes": [ - { - "FamilyName": "Risk Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", - "SubSection": "", - "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.CntrReg.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "ID.RA-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "RA-5", - "SI-5" - ] - } - ] - } - ], - "Checks": [ - "defender_container_images_scan_enabled", - "defender_container_images_resolved_vulnerabilities" - ] - }, - { - "Id": "CCC.DataWar.CN01.AR01", - "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", - "SubSection": "", - "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.DataWar.CN02.AR01", - "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", - "SubSection": "", - "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.DataWar.CN03.AR01", - "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", - "SubSection": "", - "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - } - ] - } - ], - "Checks": [ - "cosmosdb_account_use_aad_and_rbac", - "cosmosdb_account_firewall_use_selected_networks", - "cosmosdb_account_use_private_endpoints", - "sqlserver_unrestricted_inbound_access", - "postgresql_flexible_server_allow_access_services_disabled" - ] - }, - { - "Id": "CCC.KeyMgmt.CN01.AR01", - "Description": "When a key version is scheduled for deletion or disabled, an alert MUST be generated within five minutes.", - "Attributes": [ - { - "FamilyName": "Logging and Metrics Publication", - "FamilyDescription": "Controls that collect, alert, and retain key-management events.", - "Section": "CCC.KeyMgmt.CN01 Alert on Key-version Changes", - "SubSection": "", - "SubSectionObjective": "Generate near-real-time alerts when a KMS key version is disabled or scheduled for deletion, enabling rapid investigation and recovery.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use native event services (e.g., CloudWatch Events, Azure Monitor, Cloud Audit Logs) to route notifications to an incident-response channel.", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.KeyMgmt.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "RS.AN-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IR-5" - ] - } - ] - } - ], - "Checks": [ - "keyvault_logging_enabled", - "monitor_diagnostic_settings_exists", - "monitor_alert_create_update_nsg", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_service_health_exists" - ] - }, - { - "Id": "CCC.KeyMgmt.CN02.AR01", - "Description": "When IAM roles and key policies are reviewed, Decrypt permission MUST be granted exclusively to documented authorised principals.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that enforce least-privilege use of KMS operations.", - "Section": "CCC.KeyMgmt.CN02 Limit Decrypt Permissions", - "SubSection": "", - "SubSectionObjective": "Restrict the Decrypt operation to authorised principals only, applying the principle of least privilege to protect sensitive data.", - "Applicability": [ - "tlp-green" - ], - "Recommendation": "Periodically audit policy documents via automated tooling and report any deviations.", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.KeyMgmt.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-6" - ] - } - ] - } - ], - "Checks": [ - "keyvault_rbac_enabled", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set", - "keyvault_key_expiration_set_in_non_rbac" - ] - }, - { - "Id": "CCC.KeyMgmt.CN03.AR01", - "Description": "When rotation settings are examined, rotation MUST be enabled with an interval not exceeding 365 days.", - "Attributes": [ - { - "FamilyName": "Key Lifecycle Management", - "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", - "Section": "CCC.KeyMgmt.CN03 Enforce Automatic Rotation", - "SubSection": "", - "SubSectionObjective": "Ensure symmetric keys rotate automatically within policy intervals to reduce exposure of key material.", - "Applicability": [ - "tlp-green" - ], - "Recommendation": "Use cloud-provider rotation features and verify via configuration scanning.", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.KeyMgmt.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12" - ] - } - ] - } - ], - "Checks": [ - "keyvault_key_rotation_enabled" - ] - }, - { - "Id": "CCC.KeyMgmt.CN04.AR01", - "Description": "When a key import request is processed, the key MUST use an approved algorithm (RSA-2048+, EC-P256+) and originate from a certified HSM.", - "Attributes": [ - { - "FamilyName": "Key Lifecycle Management", - "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", - "Section": "CCC.KeyMgmt.CN04 Validate Imported Keys", - "SubSection": "", - "SubSectionObjective": "Accept only externally generated keys that meet approved cryptographic strength and provenance requirements.", - "Applicability": [ - "tlp-green" - ], - "Recommendation": "Implement an approval workflow that validates attestation data before import.", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.KeyMgmt.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "keyvault_key_rotation_enabled", - "keyvault_rbac_enabled", - "keyvault_key_expiration_set_in_non_rbac", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "keyvault_recoverable", - "keyvault_logging_enabled", - "keyvault_non_rbac_secret_expiration_set" - ] - }, - { - "Id": "CCC.LB.CN01.AR01", - "Description": "When a single client sends more than 2000 requests within any 5-minute sliding window, the load balancer MUST throttle all subsequent requests from that client for at least 60 seconds.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", - "SubSection": "", - "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH01", - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-1", - "PR.AC-7", - "PR.PT-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6", - "SC-5", - "AC-7" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.LB.CN01.AR02", - "Description": "When throttling is invoked, the load balancer MUST record the event in the access log within 5 minutes for alerting and trend analysis.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", - "SubSection": "", - "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH01", - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-1", - "PR.AC-7", - "PR.PT-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6", - "SC-5", - "AC-7" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "network_flow_log_captured_sent", - "network_watcher_enabled", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] - }, - { - "Id": "CCC.LB.CN06.AR01", - "Description": "When more than 10 percent of targets change from healthy to unhealthy within five minutes, an alert MUST be issued.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN06 Secure Health-Check Telemetry", - "SubSection": "", - "SubSectionObjective": "Monitor health-check endpoints for tampering and alert on abnormal status changes.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_alert_service_health_exists", - "monitor_alert_create_update_nsg", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_create_policy_assignment", - "network_flow_log_captured_sent", - "network_watcher_enabled", - "vm_scaleset_associated_with_load_balancer" - ] - }, - { - "Id": "CCC.LB.CN04.AR01", - "Description": "When routing weights change, the request MUST originate from an explicitly defined and trusted identity and MUST be logged.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN04 Enforce Distribution Policies", - "SubSection": "", - "SubSectionObjective": "Ensure traffic-splitting weights and algorithms are modified only by trusted identities.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_nsg", - "monitor_alert_create_policy_assignment", - "monitor_alert_create_update_security_solution", - "entra_global_admin_in_less_than_five_users", - "entra_non_privileged_user_has_mfa", - "iam_role_user_access_admin_restricted", - "iam_custom_role_has_permissions_to_administer_resource_locks" - ] - }, - { - "Id": "CCC.LB.CN05.AR01", - "Description": "When stickiness is enabled, session cookies MUST expire within 30 minutes of inactivity.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN05 Validate Session Affinity", - "SubSection": "", - "SubSectionObjective": "Configure session persistence to minimise fixation and hijacking risks.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Audit CCC.LB.F15 parameters via configuration scans.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-23" - ] - } - ] - } - ], - "Checks": [ - "iam_role_user_access_admin_restricted", - "iam_subscription_roles_owner_custom_not_created", - "iam_custom_role_has_permissions_to_administer_resource_locks" - ] - }, - { - "Id": "CCC.LB.CN09.AR01", - "Description": "When an API call originates outside the approved CIDR set, the request MUST be denied.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN09 Restrict Management API Access", - "SubSection": "", - "SubSectionObjective": "Limit load-balancer API calls to authorised identities and trusted networks.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Combine VPC endpoints with IAM condition-key filters for protected APIs.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH08" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_global_admin_in_less_than_five_users", - "entra_privileged_user_has_mfa", - "iam_role_user_access_admin_restricted", - "iam_custom_role_has_permissions_to_administer_resource_locks" - ] - }, - { - "Id": "CCC.LB.CN02.AR01", - "Description": "When concurrent connections reach 80 percent of capacity, the autoscaling group MUST add at least one instance within five minutes.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", - "Section": "CCC.LB.CN02 Auto-Scale Load Balancer Capacity", - "SubSection": "", - "SubSectionObjective": "Expand load-balancer capacity to maintain availability during traffic spikes.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Enable autoscaling policies.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "ID.BE-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-10" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.LB.CN07.AR01", - "Description": "When responses pass through the load balancer, the \"Server\" header MUST be replaced with \"lb\".", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", - "Section": "CCC.LB.CN07 Scrub Sensitive Headers", - "SubSection": "", - "SubSectionObjective": "Remove headers that disclose internal details or software versions from HTTP responses.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Configure header-transformation rules.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-13" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.LB.CN08.AR01", - "Description": "When a certificate is within 30 days of expiry, automated renewal MUST complete and deploy a new certificate within 24 hours.", - "Attributes": [ - { - "FamilyName": "Encryption", - "FamilyDescription": "Controls that ensure trustworthy TLS certificates and ciphers.", - "Section": "CCC.LB.CN08 Automate Certificate Renewal", - "SubSection": "", - "SubSectionObjective": "Maintain valid TLS certificates by automating renewal and deployment before expiry.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use certificate-manager auto-renewal workflows.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-6" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-17" - ] - } - ] - } - ], - "Checks": [] - }, { "Id": "CCC.Logging.CN01.AR01", "Description": "When a new cloud account is created, provider-level audit and network flow logging MUST be enabled by default and directed to the central sink.", "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", "SubSection": "", "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", @@ -1591,10 +2312,7 @@ ], "Checks": [ "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "network_flow_log_captured_sent", - "app_http_logs_enabled", - "appinsights_ensure_is_configured" + "network_flow_log_captured_sent" ] }, { @@ -1603,7 +2321,7 @@ "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", "SubSection": "", "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", @@ -1643,8 +2361,7 @@ "monitor_diagnostic_settings_exists", "monitor_diagnostic_setting_with_appropriate_categories", "app_http_logs_enabled", - "keyvault_logging_enabled", - "network_flow_log_captured_sent" + "keyvault_logging_enabled" ] }, { @@ -1653,52 +2370,7 @@ "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "GV.PO-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "network_flow_log_more_than_90_days" - ] - }, - { - "Id": "CCC.Logging.CN02.AR02", - "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", "SubSection": "", "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", @@ -1740,12 +2412,59 @@ ] }, { - "Id": "CCC.AuditLog.CN08.AR01", + "Id": "CCC.Logging.CN02.AR02", + "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "GV.PO-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "network_flow_log_more_than_90_days", + "sqlserver_auditing_retention_90_days", + "postgresql_flexible_server_log_retention_days_greater_3" + ] + }, + { + "Id": "CCC.Logging.CN03.AR01", "Description": "When an attempt is made to modify or delete data before the object lock period expires, then the action MUST be denied.", "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", "Section": "CCC.Logging.CN03 Enable Object Lock On Log Bucket", "SubSection": "", "SubSectionObjective": "Ensure log immutability by enabling Write Once, Read Many (WORM) protection using object lock on log storage buckets. This prevents logs from being modified or deleted during the defined retention period, supporting compliance and forensic integrity.", @@ -1753,12 +2472,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure object lock policy. ", + "Recommendation": "Configure object lock policy.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -1782,12 +2501,12 @@ "Checks": [] }, { - "Id": "CCC.AuditLog.CN04.AR01", + "Id": "CCC.Logging.CN04.AR01", "Description": "When restricted fields are accessed by unauthorized users, then those fields MUST remain masked.", "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", + "FamilyDescription": "Controls that restrict who can access and modify logs.", "Section": "CCC.Logging.CN04 Restrict Field And Log Type Access", "SubSection": "", "SubSectionObjective": "Configure access to logs to follow the principle of least privilege in particular where technically possible limit the log fields users have access to to prevent accidental exposure to sensitive information such as PII.", @@ -1795,7 +2514,7 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Review field level access controls on log data. ", + "Recommendation": "Review field level access controls on log data.", "SectionThreatMappings": [ { "ReferenceId": "CCC", @@ -1826,10 +2545,7 @@ } ], "Checks": [ - "monitor_diagnostic_settings_exists", - "keyvault_logging_enabled", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" + "monitor_storage_account_with_activity_logs_is_private" ] }, { @@ -1838,7 +2554,7 @@ "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", + "FamilyDescription": "Controls that restrict who can access and modify logs.", "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", "SubSection": "", "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", @@ -1847,12 +2563,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -1875,8 +2591,6 @@ ], "Checks": [ "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_diagnostic_settings_exists", "storage_blob_public_access_level_is_disabled" ] }, @@ -1886,7 +2600,7 @@ "Attributes": [ { "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", + "FamilyDescription": "Controls that restrict who can access and modify logs.", "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", "SubSection": "", "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", @@ -1895,12 +2609,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -1923,10 +2637,7 @@ ], "Checks": [ "storage_blob_public_access_level_is_disabled", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_diagnostic_settings_exists", - "storage_geo_redundant_enabled" + "monitor_storage_account_with_activity_logs_is_private" ] }, { @@ -1935,7 +2646,7 @@ "Attributes": [ { "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", "Section": "CCC.Logging.CN06 Detect and Alert on Potential Log Exfiltration", "SubSection": "", "SubSectionObjective": "Identify and alert on anomalous data access patterns that may indicate an attempt to exfiltrate log data.", @@ -1972,9 +2683,7 @@ ] } ], - "Checks": [ - "apim_threat_detection_llm_jacking" - ] + "Checks": [] }, { "Id": "CCC.Logging.CN07.AR01", @@ -1982,7 +2691,7 @@ "Attributes": [ { "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", "Section": "CCC.Logging.CN07 Detect and Alert on Log Service Tampering", "SubSection": "", "SubSectionObjective": "Alert when any component of the critical logging infrastructure is disabled, modified, or deleted, indicating a defense evasion attempt.", @@ -1997,7 +2706,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.Core.TH16" ] } ], @@ -2020,921 +2729,14 @@ ] } ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_alert_create_update_nsg", - "monitor_alert_delete_nsg", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_delete_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_delete_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_delete_policy_assignment", - "monitor_alert_service_health_exists", - "monitor_alert_create_update_sqlserver_fr", - "monitor_alert_delete_sqlserver_fr" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR01", - "Description": "When a request is made to read a protected bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "storage_ensure_encryption_with_customer_managed_keys", - "databricks_workspace_cmk_encryption_enabled", - "vm_ensure_attached_disks_encrypted_with_cmk", - "vm_ensure_unattached_disks_encrypted_with_cmk" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR02", - "Description": "When a request is made to read a protected object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "storage_ensure_encryption_with_customer_managed_keys", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "keyvault_rbac_enabled", - "keyvault_private_endpoints", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR03", - "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "storage_ensure_encryption_with_customer_managed_keys", - "storage_ensure_private_endpoints_in_storage_accounts", - "keyvault_rbac_enabled", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR04", - "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "storage_ensure_encryption_with_customer_managed_keys", - "databricks_workspace_cmk_encryption_enabled", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR01", - "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled", - "storage_ensure_soft_delete_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR02", - "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], "Checks": [] }, - { - "Id": "CCC.ObjStor.CN04.AR01", - "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled", - "storage_ensure_soft_delete_is_enabled", - "storage_ensure_file_shares_soft_delete_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN04.AR02", - "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "storage_ensure_soft_delete_is_enabled", - "storage_ensure_file_shares_soft_delete_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR01", - "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR02", - "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR03", - "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR04", - "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_versioning_is_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN06.AR01", - "Description": "When an object storage bucket is accessed, the service MUST store access logs in a separate data store.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN06 Prevent Deployment in Restricted Regions", - "SubSection": "CCC.ObjStor.C06 Access Logs are Stored in a Separate Data Store", - "SubSectionObjective": "Ensure that access logs for object storage buckets are stored in a separate data store to protect against unauthorized access, tampering, or deletion of logs (Logbuckets are exempt from this requirement, but must be tlp-red).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH07", - "CCC.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-07", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.15.0" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] - }, - { - "Id": "CCC.ObjStor.CN02.AR01", - "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_public_access_level_is_disabled", - "storage_default_network_access_rule_is_denied", - "storage_ensure_private_endpoints_in_storage_accounts" - ] - }, - { - "Id": "CCC.ObjStor.CN02.AR02", - "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] - } - ] - } - ], - "Checks": [ - "storage_blob_public_access_level_is_disabled", - "storage_account_key_access_disabled", - "storage_default_to_entra_authorization_enabled", - "storage_ensure_private_endpoints_in_storage_accounts" - ] - }, { "Id": "CCC.Monitor.CN01.AR01", "Description": "When an External Monitoring system exceeds the anticipated rate of monitoring checks then Rate Limiting MUST be applied and an Audit Alert MUST be generated.", "Attributes": [ { - "FamilyName": "Logging & Monitoring", + "FamilyName": "Logging and Monitoring", "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", "Section": "CCC.Monitor.CN01 Rate Limiting on External Monitoring", "SubSection": "", @@ -2972,25 +2774,14 @@ ] } ], - "Checks": [ - "monitor_alert_create_update_sqlserver_fr", - "monitor_alert_delete_nsg", - "monitor_alert_delete_public_ip_address_rule", - "monitor_alert_delete_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_create_update_nsg", - "monitor_alert_service_health_exists", - "monitor_diagnostic_settings_exists" - ] + "Checks": [] }, { "Id": "CCC.Monitor.CN02.AR01", "Description": "When an Custom or User-Defined Metric starts to flood a collector, then a rate limit MUST be applied to reduce the network impact of traffic and an alert must triggered.", "Attributes": [ { - "FamilyName": "Logging & Monitoring", + "FamilyName": "Logging and Monitoring", "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", "Section": "CCC.Monitor.CN02 Rate Limiting on Metric Generation", "SubSection": "", @@ -3028,9 +2819,7 @@ ] } ], - "Checks": [ - "apim_threat_detection_llm_jacking" - ] + "Checks": [] }, { "Id": "CCC.Monitor.CN03.AR01", @@ -3075,10 +2864,7 @@ ] } ], - "Checks": [ - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] + "Checks": [] }, { "Id": "CCC.Monitor.CN04.AR01", @@ -3146,7 +2932,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH10" + "CCC.Core.TH10" ] } ], @@ -3212,11 +2998,1111 @@ ], "Checks": [ "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "app_function_access_keys_configured", - "app_function_not_publicly_accessible", - "app_register_with_identity", - "app_ensure_auth_is_set_up" + "app_function_access_keys_configured" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR01", + "Description": "When a request is made to read a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "keyvault_rbac_enabled", + "keyvault_private_endpoints" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR02", + "Description": "When a request is made to read an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "keyvault_rbac_enabled", + "keyvault_private_endpoints" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR03", + "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "keyvault_rbac_enabled", + "keyvault_private_endpoints" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR04", + "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_encryption_with_customer_managed_keys", + "keyvault_rbac_enabled", + "keyvault_private_endpoints" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR01", + "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_soft_delete_is_enabled", + "storage_blob_versioning_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR02", + "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR01", + "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_soft_delete_is_enabled", + "storage_ensure_file_shares_soft_delete_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR02", + "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_ensure_soft_delete_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR01", + "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_blob_versioning_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR02", + "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_blob_versioning_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR03", + "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_blob_versioning_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR04", + "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "storage_blob_versioning_is_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN07.AR01", + "Description": "The object storage service MUST support a configuration option that requires MFA to be successfully completed before any object deletion can be attempted, regardless of the request interface.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN07.AR02", + "Description": "When MFA deletion protection is enabled on a bucket or object namespace, the service MUST deny any deletion request from an identity that has not satisfied the MFA requirement at the time of the request.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN07.AR03", + "Description": "When an attempt is made to delete an object, the service's audit logs MUST clearly record each deletion attempt, including whether MFA was required and whether validation was met.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN02.AR01", + "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", + "SubSection": "", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + } + ] + } + ], + "Checks": [ + "storage_account_key_access_disabled", + "storage_default_to_entra_authorization_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN02.AR02", + "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", + "SubSection": "", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + } + ] + } + ], + "Checks": [ + "storage_account_key_access_disabled", + "storage_default_to_entra_authorization_enabled" + ] + }, + { + "Id": "CCC.LB.CN01.AR01", + "Description": "When a single client sends more than 2000 requests within any 5-minute sliding window, the load balancer MUST throttle all subsequent requests from that client for at least 60 seconds.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", + "SubSection": "", + "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH01", + "CCC.LB.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-1", + "PR.AC-7", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-6", + "SC-5", + "AC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN01.AR02", + "Description": "When throttling is invoked, the load balancer MUST record the event in the access log within 5 minutes for alerting and trend analysis.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", + "SubSection": "", + "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH01", + "CCC.LB.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-1", + "PR.AC-7", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-6", + "SC-5", + "AC-7" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists" + ] + }, + { + "Id": "CCC.LB.CN06.AR01", + "Description": "When more than 10 percent of targets change from healthy to unhealthy within five minutes, an alert MUST be issued.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN06 Secure Health-Check Telemetry", + "SubSection": "", + "SubSectionObjective": "Monitor health-check endpoints for tampering and alert on abnormal status changes.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.AE-2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4" + ] + } + ] + } + ], + "Checks": [ + "monitor_alert_service_health_exists" + ] + }, + { + "Id": "CCC.LB.CN04.AR01", + "Description": "When routing weights change, the request MUST originate from an explicitly defined and trusted identity and MUST be logged.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN04 Enforce Distribution Policies", + "SubSection": "", + "SubSectionObjective": "Ensure traffic-splitting weights and algorithms are modified only by trusted identities.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists" + ] + }, + { + "Id": "CCC.LB.CN05.AR01", + "Description": "When stickiness is enabled, session cookies MUST expire within 30 minutes of inactivity.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN05 Validate Session Affinity", + "SubSection": "", + "SubSectionObjective": "Configure session persistence to minimise fixation and hijacking risks.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Audit CCC.LB.CP15 parameters via configuration scans.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-23" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN09.AR01", + "Description": "When an API call originates outside the approved CIDR set, the request MUST be denied.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN09 Restrict Management API Access", + "SubSection": "", + "SubSectionObjective": "Limit load-balancer API calls to authorised identities and trusted networks.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Combine VPC endpoints with IAM condition-key filters for protected APIs.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH08" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "entra_conditional_access_policy_require_mfa_for_management_api" + ] + }, + { + "Id": "CCC.LB.CN02.AR01", + "Description": "When concurrent connections reach 80 percent of capacity, the autoscaling group MUST add at least one instance within five minutes.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", + "Section": "CCC.LB.CN02 Auto-Scale Load Balancer Capacity", + "SubSection": "", + "SubSectionObjective": "Expand load-balancer capacity to maintain availability during traffic spikes.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Enable autoscaling policies.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.BE-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "CP-10" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN07.AR01", + "Description": "When responses pass through the load balancer, the \"Server\" header MUST be replaced with \"lb\".", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", + "Section": "CCC.LB.CN07 Scrub Sensitive Headers", + "SubSection": "", + "SubSectionObjective": "Remove headers that disclose internal details or software versions from HTTP responses.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Configure header-transformation rules.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-13" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN08.AR01", + "Description": "When a certificate is within 30 days of expiry, automated renewal MUST complete and deploy a new certificate within 24 hours.", + "Attributes": [ + { + "FamilyName": "Encryption", + "FamilyDescription": "Controls that ensure trustworthy TLS certificates and ciphers.", + "Section": "CCC.LB.CN08 Automate Certificate Renewal", + "SubSection": "", + "SubSectionObjective": "Maintain valid TLS certificates by automating renewal and deployment before expiry.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use certificate-manager auto-renewal workflows.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-17" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" ] }, { @@ -3272,6 +4158,58 @@ ], "Checks": [] }, + { + "Id": "CCC.VPC.CN02.AR01", + "Description": "When a resource is created in a public subnet, that resource MUST NOT be assigned an external IP address by default.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN02 Limit Resource Creation in Public Subnet", + "SubSection": "", + "SubSectionObjective": "Restrict the creation of resources in the public subnet with direct access to the internet to minimize attack surfaces.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.VPC.CN03.AR01", "Description": "When a VPC peering connection is requested, the service MUST prevent connections from VPCs that are not explicitly allowed.", @@ -3379,10 +4317,393 @@ ], "Checks": [ "network_flow_log_captured_sent", - "network_flow_log_more_than_90_days", "network_watcher_enabled" ] }, + { + "Id": "CCC.KeyMgmt.CN01.AR01", + "Description": "When a key version is scheduled for deletion or disabled, an alert MUST be generated within five minutes.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain key-management events.", + "Section": "CCC.KeyMgmt.CN01 Alert on Key-version Changes", + "SubSection": "", + "SubSectionObjective": "Generate near-real-time alerts when a KMS key version is disabled or scheduled for deletion, enabling rapid investigation and recovery.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use native event services (e.g., CloudWatch Events, Azure Monitor, Cloud Audit Logs) to route notifications to an incident-response channel.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "RS.AN-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IR-5" + ] + } + ] + } + ], + "Checks": [ + "keyvault_logging_enabled", + "keyvault_recoverable" + ] + }, + { + "Id": "CCC.KeyMgmt.CN02.AR01", + "Description": "When IAM roles and key policies are reviewed, Decrypt permission MUST be granted exclusively to documented authorised principals.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that enforce least-privilege use of KMS operations.", + "Section": "CCC.KeyMgmt.CN02 Limit Decrypt Permissions", + "SubSection": "", + "SubSectionObjective": "Restrict the Decrypt operation to authorised principals only, applying the principle of least privilege to protect sensitive data.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Periodically audit policy documents via automated tooling and report any deviations.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "keyvault_rbac_enabled", + "keyvault_access_only_through_private_endpoints" + ] + }, + { + "Id": "CCC.KeyMgmt.CN03.AR01", + "Description": "When rotation settings are examined, rotation MUST be enabled with an interval not exceeding 365 days.", + "Attributes": [ + { + "FamilyName": "Key Lifecycle Management", + "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", + "Section": "CCC.KeyMgmt.CN03 Enforce Automatic Rotation", + "SubSection": "", + "SubSectionObjective": "Ensure symmetric keys rotate automatically within policy intervals to reduce exposure of key material.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Use cloud-provider rotation features and verify via configuration scanning.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-12" + ] + } + ] + } + ], + "Checks": [ + "keyvault_key_rotation_enabled" + ] + }, + { + "Id": "CCC.KeyMgmt.CN04.AR01", + "Description": "When a key import request is processed, the key MUST use an approved algorithm (RSA-2048+, EC-P256+) and originate from a certified HSM.", + "Attributes": [ + { + "FamilyName": "Key Lifecycle Management", + "FamilyDescription": "Controls that govern creation, rotation, import, and retirement of cryptographic keys.", + "Section": "CCC.KeyMgmt.CN04 Validate Imported Keys", + "SubSection": "", + "SubSectionObjective": "Accept only externally generated keys that meet approved cryptographic strength and provenance requirements.", + "Applicability": [ + "tlp-green" + ], + "Recommendation": "Implement an approval workflow that validates attestation data before import.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.KeyMgmt.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-28" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.SecMgmt.CN01.AR01", + "Description": "Attempt to use an outdated version of a secret after its rotation period has passed and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN01 Enforce Automatic Secret Rotation", + "SubSection": "", + "SubSectionObjective": "Ensure that secrets are automatically rotated on a defined schedule to reduce the risk of secret compromise and unauthorized access.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH14" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-12", + "SC-28" + ] + } + ] + } + ], + "Checks": [ + "keyvault_rbac_secret_expiration_set", + "keyvault_non_rbac_secret_expiration_set" + ] + }, + { + "Id": "CCC.SecMgmt.CN02.AR01", + "Description": "Attempt to retrieve a secret from an unauthorized region and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN02 Enforce Secret Replication Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that secrets are replicated only to authorized locations as per organizational data residency and compliance requirements.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN01.AR01", + "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", + "SubSection": "", + "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN02.AR01", + "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN03.AR01", + "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.Vector.CN01.AR01", "Description": "When a vector embedding is submitted for indexing, the system MUST validate that it matches expected schema, dimension, and format profiles.", @@ -3406,7 +4727,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH05", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3445,7 +4766,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH04", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3459,13 +4780,7 @@ ] } ], - "Checks": [ - "iam_role_user_access_admin_restricted", - "iam_custom_role_has_permissions_to_administer_resource_locks", - "iam_subscription_roles_owner_custom_not_created", - "app_function_identity_without_admin_privileges", - "app_function_identity_is_configured" - ] + "Checks": [] }, { "Id": "CCC.Vector.CN03.AR01", @@ -3487,7 +4802,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH03", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3526,7 +4841,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH02", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3562,8 +4877,8 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH04", - "CCC.TH09", - "CCC.TH04" + "CCC.Core.TH09", + "CCC.Core.TH04" ] } ], @@ -3601,7 +4916,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH05", - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -3646,451 +4961,25 @@ "Checks": [] }, { - "Id": "CCC.Core.CN01.AR01", - "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Id": "CCC.RDMS.CN01.AR02", + "Description": "When an attempt is made to authenticate to the database using known default credentials, the authentication attempt must fail and no access should be granted.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN01 Password Management", "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "app_minimum_tls_version_12", - "app_ensure_http_is_redirected_to_https", - "storage_secure_transfer_required_is_enabled", - "storage_ensure_minimum_tls_version_12" - ] - }, - { - "Id": "CCC.Core.CN01.AR02", - "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "network_ssh_internet_access_restricted", - "vm_linux_enforce_ssh_authentication", - "app_minimum_tls_version_12", - "storage_secure_transfer_required_is_enabled", - "storage_ensure_minimum_tls_version_12", - "app_ensure_http_is_redirected_to_https" - ] - }, - { - "Id": "CCC.Core.CN01.AR03", - "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "app_ensure_http_is_redirected_to_https", - "app_minimum_tls_version_12", - "storage_secure_transfer_required_is_enabled", - "storage_ensure_minimum_tls_version_12", - "app_ftp_deployment_disabled" - ] - }, - { - "Id": "CCC.Core.CN01.AR07", - "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "app_minimum_tls_version_12", - "app_ensure_http_is_redirected_to_https", - "app_ensure_using_http20", - "storage_smb_channel_encryption_with_secure_algorithm", - "storage_secure_transfer_required_is_enabled", - "storage_ensure_minimum_tls_version_12", - "storage_smb_protocol_version_is_latest" - ] - }, - { - "Id": "CCC.Core.CN01.AR08", - "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "app_client_certificates_on", - "app_minimum_tls_version_12", - "app_ensure_http_is_redirected_to_https" - ] - }, - { - "Id": "CCC.Core.CN13.AR01", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "app_client_certificates_on", - "app_minimum_tls_version_12", - "keyvault_key_expiration_set_in_non_rbac", - "keyvault_key_rotation_enabled", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set", - "keyvault_non_rbac_secret_expiration_set" - ] - }, - { - "Id": "CCC.Core.CN13.AR02", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "SubSectionObjective": "Ensure default vendor-supplied DB administrator credentials are replaced with strong, unique passwords and that these credentials are properly managed using a secure password or secrets management solution.", "Applicability": [ + "tlp-red", "tlp-amber" ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "keyvault_key_rotation_enabled", - "keyvault_key_expiration_set_in_non_rbac", - "keyvault_rbac_key_expiration_set", - "keyvault_non_rbac_secret_expiration_set", - "keyvault_rbac_secret_expiration_set", - "storage_ensure_encryption_with_customer_managed_keys" - ] - }, - { - "Id": "CCC.Core.CN13.AR03", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "app_client_certificates_on", - "app_ensure_http_is_redirected_to_https", - "app_minimum_tls_version_12" - ] - }, - { - "Id": "CCC.Core.CN06.AR01", - "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", - "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH01" ] } ], @@ -4098,19 +4987,89 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.AA-01" ] }, { - "ReferenceId": "CCM", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "DSP-19" + "AC-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN02.AR01", + "Description": "When repeated failed login attempts are made in a short timeframe, the account must be locked out or rate-limited to prevent further login attempts.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN02 Account Lockout and Rate-Limiting", + "SubSection": "", + "SubSectionObjective": "Ensure the database enforces lockouts or rate-limiting after a specified number of failed authentication attempts. This prevents brute force or password-guessing attacks from succeeding.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-1" ] }, { - "ReferenceId": "ISO_27001", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "2013 A.11.1.1" + "AC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN04.AR01", + "Description": "When there is an attempt to perform a backup or restore, then the attempt must fail with an access denied message if credentials or roles that are not explicitly authorized for backup/restore functions.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN04 Access Control for Backup and Restore Operations", + "SubSection": "", + "SubSectionObjective": "Restrict who can initiate, manage, and validate database backup or restore operations through strict role-based or least-privilege access. Prevents accidental or malicious restorations, protecting data integrity and availability.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" ] }, { @@ -4122,44 +5081,28 @@ ] } ], - "Checks": [ - "aks_clusters_public_access_disabled", - "aks_clusters_created_with_private_nodes", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "storage_ensure_private_endpoints_in_storage_accounts", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted", - "network_watcher_enabled", - "entra_trusted_named_locations_exists" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN06.AR02", - "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Id": "CCC.RDMS.CN05.AR01", + "Description": "When an attempt is made to share a snapshot with an unauthorized account, the sharing request must be denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN05 Restrict Snapshot Sharing to Authorized Accounts", "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Ensure database snapshots can only be shared with explicitly authorized accounts, thereby minimizing the risk of data exposure or exfiltration.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH05" ] } ], @@ -4167,24 +5110,312 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-19" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.11.1.1" + "PR.DS-10" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN03.AR01", + "Description": "When backups are disabled, paused, or fail to run as scheduled, an alert must be triggered and logged.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN03 Enforce and Monitor Automated Backups", + "SubSection": "", + "SubSectionObjective": "Ensure database backups are automatically scheduled, actively monitored, and promptly reported if any disruptions occur. This helps maintain data integrity, facilitates disaster recovery, and supports business continuity when a system failure or breach occurs.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "CP-9" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Build.CN01.AR01", + "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", + "Attributes": [ + { + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN01 Restrict Allowed Build Agents", + "SubSection": "", + "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Build.CN02.AR01", + "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", + "Attributes": [ + { + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN02 Restrict Allowed External Services for Build Triggers", + "SubSection": "", + "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Build.CN03.AR01", + "Description": "Attempt to access the build environment from an external network and verify that access is denied.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN03 Deny External Network Access for Build Environments", + "SubSection": "", + "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02", + "CCC.Core.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-5" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.CntrReg.CN01.AR01", + "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", + "Attributes": [ + { + "FamilyName": "Risk Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.CntrReg.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "RA-5", + "SI-5" + ] + } + ] + } + ], + "Checks": [ + "defender_container_images_scan_enabled", + "defender_container_images_resolved_vulnerabilities" + ] + }, + { + "Id": "CCC.CntrReg.CN02.AR01", + "Description": "Confirm that artifacts older than the specified retention period are automatically deleted from the registry.", + "Attributes": [ + { + "FamilyName": "Data Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN02 Implement Cleanup Policies for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that unused or outdated artifacts are cleaned up according to defined policies to manage storage effectively and reduce security risks associated with outdated versions.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH14" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN01.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials or generating temporary session tokens.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", + "SubSection": "", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-5", "AC-6" ] } @@ -4192,127 +5423,20 @@ } ], "Checks": [ - "entra_trusted_named_locations_exists" + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps" ] }, { - "Id": "CCC.Core.CN08.AR01", - "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Id": "CCC.IAM.CN01.AR02", + "Description": "When a non-administrative principal attempts to create new credentials or a temporary session token, the service MUST deny the action.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-2", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "storage_geo_redundant_enabled", - "vm_backup_enabled", - "vm_sufficient_daily_backup_retention_period" - ] - }, - { - "Id": "CCC.Core.CN08.AR02", - "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", - "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-2", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "storage_geo_redundant_enabled" - ] - }, - { - "Id": "CCC.Core.CN09.AR01", - "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", "Applicability": [ "tlp-clear", "tlp-green", @@ -4324,9 +5448,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH03" ] } ], @@ -4334,57 +5456,48 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "monitor_diagnostic_settings_exists", - "network_flow_log_captured_sent", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" + "entra_policy_default_users_cannot_create_security_groups", + "entra_policy_ensure_default_user_cannot_create_apps" ] }, { - "Id": "CCC.Core.CN09.AR02", - "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Id": "CCC.IAM.CN02.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating, updating, or attaching policies.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", "Applicability": [ "tlp-clear", "tlp-green", "tlp-amber", "tlp-red" ], - "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH06" ] } ], @@ -4392,57 +5505,49 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private", - "keyvault_logging_enabled", - "app_http_logs_enabled" + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "iam_custom_role_has_permissions_to_administer_resource_locks" ] }, { - "Id": "CCC.Core.CN09.AR03", - "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Id": "CCC.IAM.CN02.AR02", + "Description": "When a non-administrative principal attempts to create, update, or attach policies, the service MUST deny the action.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", "Applicability": [ + "tlp-clear", + "tlp-green", "tlp-amber", "tlp-red" ], - "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH06" ] } ], @@ -4450,46 +5555,37 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "network_flow_log_captured_sent", - "app_http_logs_enabled", - "keyvault_logging_enabled" + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "iam_custom_role_has_permissions_to_administer_resource_locks" ] }, { - "Id": "CCC.Core.CN10.AR01", - "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", + "Id": "CCC.IAM.CN03.AR01", + "Description": "When a policy is created or updated that grants a principal permission to assume a role or impersonate a service identity, the principal MUST NOT contain a wildcard or be public/anonymous.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", "SubSection": "", - "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", "Applicability": [ "tlp-green", "tlp-amber", @@ -4500,7 +5596,1438 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH04" + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_user_access_admin_restricted" + ] + }, + { + "Id": "CCC.IAM.CN03.AR02", + "Description": "When an external or unauthenticated principal tries to assume a role or impersonate a service identity, the service MUST deny the action.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", + "SubSection": "", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_user_access_admin_restricted" + ] + }, + { + "Id": "CCC.IAM.CN04.AR01", + "Description": "When an IAM policy is created or updated, it MUST NOT contain allow statements with wildcard permissions, unless the statement is restricted by a condition.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN04 Restrict Wildcard Usage in IAM Policies", + "SubSection": "", + "SubSectionObjective": "Limit the use of wildcard permissions in IAM policies to prevent overly broad access from being granted by default.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN05.AR01", + "Description": "When a new cloud account is provisioned, a password policy MUST be configured for IAM users following the minimum PCI DSS v4.0.1 configurations.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN05 Strong Password Policies for IAM Users", + "SubSection": "", + "SubSectionObjective": "Ensure that the password policies for IAM users have strong configurations.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a new cloud account is provisioned, a password policy must be configured for all IAM users to align with the minimum requirements defined in PCI DSS v4.0.1. This includes, at a minimum: strength: 0 # Not yet specified - reference-id: A password length of at least 12 characters. strength: 0 # Not yet specified - reference-id: A mix of upper- and lower-case letters, numbers, and special characters. strength: 0 # Not yet specified - reference-id: Prevention of the use of previously used passwords (password history). strength: 0 # Not yet specified - reference-id: Password expiration at a defined interval (e.g., every 90 days). strength: 0 # Not yet specified - reference-id: Account lockout after a defined number of failed login attempts.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-5" + ] + }, + { + "ReferenceId": "PCI-DSS", + "Identifiers": [ + "8.3.9", + "8.6.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN06.AR01", + "Description": "When a static credential such as an access key has existed for 90 days or more, it MUST be rotated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN06 Maximum Age for Long-Term Static Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that long-lived static credentials like access keys are programmatically rotated within a defined time period to limit the window of opportunity if compromised.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a static credential such as an access key has existed for 90 days or more, it must be automatically rotated to reduce the risk of compromise due to long-term exposure. Organizations should implement automated checks to identify aging credentials and enforce rotation policies. Additionally, access key usage should be regularly monitored, and credentials that are no longer in use should be deactivated or deleted promptly. Where possible, prefer temporary, short-lived credentials over long-lived static ones to further minimize risk.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH09", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN07.AR01", + "Description": "When a user account is disabled or deleted in the organization's IdP, the corresponding cloud identity and its access policies MUST be disabled or deleted within 24 hours.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN07 Automate Identity De-provisioning", + "SubSection": "", + "SubSectionObjective": "Ensure that when an identity is terminated in the central Identity Provider (IdP), ts corresponding access to cloud resources is revoked automatically.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH10", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN08.AR01", + "Description": "When an IAM user has credentials, such as passwords or access keys, that have not been used for 90 days or more, the unused credentials MUST be removed or deactivated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN08 Maximum Age for Unused Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that unused IAM credentals are removed to reduce exposure in the event of potential compromise.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "IAM user credentials (such as passwords or access keys) that have not been used for 90 days or more must be automatically removed or deactivated.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH11", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN09.AR01", + "Description": "When a human user accesses the cloud environment, they MUST authenticate through the organization's federated IdP via a standard protocol (e.g., SAML, OIDC).", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN09 Enforce Federated Single Sign-On (SSO) for Human Users", + "SubSection": "", + "SubSectionObjective": "Ensure that all human users must authenticate through a central, federated Identity Provider (IdP) to access the cloud environment. This eliminates cloud-native user accounts with long-lived passwords, centralizes authentication controls, and simplifies lifecycle management.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-2" + ] + } + ] + } + ], + "Checks": [ + "entra_security_defaults_enabled" + ] + }, + { + "Id": "CCC.IAM.CN10.AR01", + "Description": "When suspicious API requests are detected, real time alerts MUST be generated to notify security personnel.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists" + ] + }, + { + "Id": "CCC.IAM.CN10.AR02", + "Description": "When suspicious API requests are detected, the associated events MUST be logged, including the source details, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "monitor_diagnostic_settings_exists", + "monitor_diagnostic_setting_with_appropriate_categories" + ] + }, + { + "Id": "CCC.IAM.CN11.AR01", + "Description": "When a cloud account or organization is provisioned, the native automated access and usage analysis services MUST be enabled to continuously monitor for external or public access to resources, and unused access.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN11 Enable Continuous IAM Access and Usage Analysis", + "SubSection": "", + "SubSectionObjective": "Enable and configure the cloud provider's native access and usage analysis services to continuously monitor for external access paths and internal unused access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02", + "CCC.IAM.TH10", + "CCC.IAM.TH11" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-01", + "ID.IM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "CA-7", + "RA-5" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN01.AR01", + "Description": "Untrusted input such as user queries, RAG data or tool output MUST be validated before it is passed to a GenAI model.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN01.AR02", + "Description": "If malicious patterns such as prompt injection or sensitive data are detected during input validation, the input MUST be blocked or sanitised.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN02.AR01", + "Description": "GenAI model output MUST be validated for format conformance, malicious patterns, sensitive data and inapropriate content before being passed to users, application or plugins.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN02.AR02", + "Description": "In the event of policy violations, the AI-generated content MUST be redacted, encoded or rejected.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN03.AR01", + "Description": "When data is designated for model training or RAG ingestion, then its source MUST be explicitly approved and its provenance documented.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN03.AR02", + "Description": "Data from unvetted sources MUST NOT be used in production systems.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN04.AR01", + "Description": "When data is ingested for training, fine-tuning or conversion to vector embeddings, it MUST be validated for sensitive information or malicious content.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN04.AR02", + "Description": "If sensitive data or malicious content is detected, it must be rejected, redacted or flagged for manual review.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN05.AR01", + "Description": "When a RAG-enabled system generates a response containing information retrieved from its knowledge base, then the response MUST include a verifiable citation that links back to the specific source document.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN05 Citations and Source Traceability", + "SubSection": "", + "SubSectionObjective": "Require the GenAI system to provide citations or direct links back to the source documents used to generate a response, in to enhance the transparency, trustworthiness, and verifiability of AI-generated content.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH09", + "CCC.GenAI.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-DET-013" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN06.AR01", + "Description": "When an LLM invokes an external tool (e.g., an API, a plugin), then the tool MUST operate with the least privileges required for performing its intended functionality.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.GenAI.CN06 Least Privilege for Plugins", + "SubSection": "", + "SubSectionObjective": "Restricts the permissions of any external tools the GenAI system can call to limit the potential damage if an agent is coerced to perform unintended actions or vulnerabilities in the tools are exploited.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH07", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Agent Permissions" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN07.AR01", + "Description": "When an application makes an API call to a foundational model in a production environment, then it MUST specify an explicit version identifier.", + "Attributes": [ + { + "FamilyName": "Configuration Management", + "FamilyDescription": "The Configuration Management control family involves establishing, maintaining and monitoring the configuration of the service and related applications and infrastructure to ensure consistency, secure defaults and compliance.", + "Section": "CCC.GenAI.CN07 Model Version Pinning", + "SubSection": "", + "SubSectionObjective": "Mandate that applications are locked (\"pinned\") to a specific, tested version of a foundational model to prevent unexpected behaviour changes introduced by provider-side updates.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-010" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR01", + "Description": "When a new AI model is considered for production deployment, it MUST undergo a formal red teaming and quality assurance review.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR02", + "Description": "If model quality review or red teaming identifies an issue that exceeds the organization's risk tolerance, the model MUST NOT be deployed until the issue is remediated.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN01.AR01", + "Description": "Verify that only authorized users can access MLDE resources, and that access modes are properly defined and enforced.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN01 Define Access Mode for ML Development Environments", + "SubSection": "", + "SubSectionObjective": "Ensure that access to Machine Learning Development Environment (MLDE) resources is strictly defined and controlled. Only authorized users with appropriate permissions can access these environments, mitigating the risk of unauthorized access, data leakage, or service disruption.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.1", + "2013 A.9.2.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-02" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN03.AR01", + "Description": "Verify that root access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN03.AR02", + "Description": "For MLDE instances without sensitive data, ensure that root access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN04.AR01", + "Description": "Verify that terminal access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN04.AR02", + "Description": "For MLDE instances without sensitive data, ensure that terminal access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN02.AR01", + "Description": "Confirm that file download functionality is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.Core.TH02" ] } ], @@ -4514,168 +7041,98 @@ { "ReferenceId": "CCM", "Identifiers": [ - "DSP-10", - "DSP-19" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-4" - ] - } - ] - } - ], - "Checks": [ - "storage_cross_tenant_replication_disabled", - "cosmosdb_account_firewall_use_selected_networks", - "cosmosdb_account_use_private_endpoints", - "containerregistry_uses_private_link", - "keyvault_private_endpoints", - "storage_ensure_private_endpoints_in_storage_accounts" - ] - }, - { - "Id": "CCC.Core.CN02.AR01", - "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN02 Encrypt Data for Storage", - "SubSection": "", - "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "UEM-08", - "DSP-17" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-13", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "storage_infrastructure_encryption_is_enabled", - "storage_ensure_encryption_with_customer_managed_keys", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "vm_ensure_attached_disks_encrypted_with_cmk", - "vm_ensure_unattached_disks_encrypted_with_cmk", - "sqlserver_tde_encrypted_with_cmk", - "sqlserver_tde_encryption_enabled", - "databricks_workspace_cmk_encryption_enabled" - ] - }, - { - "Id": "CCC.Core.CN11.AR01", - "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "DSI-05", + "DSI-07" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.13.2.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "SC-7", + "SC-8" ] } ] } ], - "Checks": [ - "storage_ensure_encryption_with_customer_managed_keys", - "databricks_workspace_cmk_encryption_enabled", - "keyvault_key_rotation_enabled", - "keyvault_key_expiration_set_in_non_rbac", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set", - "keyvault_non_rbac_secret_expiration_set", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "storage_smb_channel_encryption_with_secure_algorithm", - "storage_secure_transfer_required_is_enabled", - "storage_ensure_minimum_tls_version_12" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR02", - "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Id": "CCC.MLDE.CN02.AR02", + "Description": "For MLDE instances without sensitive data, ensure that file downloads are monitored and logged.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-5" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSI-05", + "DSI-07" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.2.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-8" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN05.AR01", + "Description": "Verify that only approved VM and container images can be selected when creating MLDE instances.", + "Attributes": [ + { + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", + "Applicability": [ + "tlp-red", "tlp-amber" ], "Recommendation": "", @@ -4683,7 +7140,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4691,51 +7148,43 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "keyvault_key_rotation_enabled", - "storage_key_rotation_90_days", - "databricks_workspace_cmk_encryption_enabled" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR03", - "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Id": "CCC.MLDE.CN05.AR02", + "Description": "Attempt to create an MLDE instance with an unapproved image and confirm that it is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "", - "SubSection": "CCC.Core.CN11 Protect Encryption Keys", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", "Applicability": [ - "tlp-amber", "tlp-red" ], "Recommendation": "", @@ -4743,7 +7192,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4751,52 +7200,371 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "databricks_workspace_cmk_encryption_enabled", - "storage_ensure_encryption_with_customer_managed_keys", - "vm_ensure_attached_disks_encrypted_with_cmk", - "vm_ensure_unattached_disks_encrypted_with_cmk", - "sqlserver_tde_encrypted_with_cmk", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR04", - "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Id": "CCC.MLDE.CN06.AR01", + "Description": "Verify that automatic scheduled upgrades are enabled on user-managed MLDE instances containing sensitive data.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH04", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-12" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-01", + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.6.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN06.AR02", + "Description": "Ensure that the upgrade schedule is appropriately configured and does not interfere with critical operations.", + "Attributes": [ + { + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH04", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-12" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-01", + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.6.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN07.AR01", + "Description": "Verify that MLDE instances containing sensitive data cannot be accessed via public IP addresses.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN07.AR02", + "Description": "For MLDE instances without sensitive data requiring public access, ensure that appropriate security controls are in place and access is approved.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN08.AR01", + "Description": "Verify that MLDE instances containing sensitive data can only be deployed in approved virtual networks with appropriate security controls.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN08.AR02", + "Description": "Ensure that MLDE instances without sensitive data are deployed in networks that meet organizational security standards.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Message.CN01.AR01", + "Description": "Attempt to publish a message without using a customer-managed encryption key and verify that the message is rejected or not stored.", + "Attributes": [ + { + "FamilyName": "Encryption", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Message.CN01 Use Customer-Managed Encryption Keys (CMEK) for Messages", + "SubSection": "", + "SubSectionObjective": "Ensure that messages are encrypted using customer-managed encryption keys (CMEK) to provide enhanced control over encryption processes and keys, meeting compliance and security requirements.", "Applicability": [ "tlp-clear", "tlp-green", @@ -4808,7 +7576,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.Core.TH01" ] } ], @@ -4819,546 +7587,82 @@ "PR.DS-1" ] }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "SC-12", - "SC-17" + "SC-13" ] } ] } ], - "Checks": [ - "databricks_workspace_cmk_encryption_enabled", - "keyvault_rbac_enabled", - "keyvault_key_rotation_enabled", - "keyvault_key_expiration_set_in_non_rbac", - "keyvault_rbac_key_expiration_set", - "keyvault_access_only_through_private_endpoints", - "keyvault_private_endpoints", - "keyvault_logging_enabled", - "keyvault_recoverable", - "storage_ensure_encryption_with_customer_managed_keys" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR05", - "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Id": "CCC.SvlsComp.CN01.AR01", + "Description": "Attempt to access the serverless function over the public internet and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN01 Enforce Use of Private Endpoints for Serverless Function", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Ensure that the serverless function is accessible only through a private endpoint, allowing it to communicate securely within a virtual private network and preventing unauthorized external access.", "Applicability": [ - "tlp-clear", - "tlp-green" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "keyvault_key_rotation_enabled", - "storage_ensure_encryption_with_customer_managed_keys", - "databricks_workspace_cmk_encryption_enabled", - "storage_key_rotation_90_days", - "keyvault_rbac_key_expiration_set", - "keyvault_rbac_secret_expiration_set", - "keyvault_key_expiration_set_in_non_rbac" - ] - }, - { - "Id": "CCC.Core.CN11.AR06", - "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "keyvault_key_rotation_enabled" - ] - }, - { - "Id": "CCC.Core.CN14.AR01", - "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "vm_backup_enabled", - "vm_sufficient_daily_backup_retention_period" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", + "tlp-red", "tlp-amber" ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH01" ] } ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "vm_backup_enabled", - "vm_sufficient_daily_backup_retention_period" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days. ", - "SectionThreatMappings": [ + "SectionGuidelineMappings": [ { - "ReferenceId": "CCC", + "ReferenceId": "NIST-CSF", "Identifiers": [ - "CCC.TH06" + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-8" ] } - ], - "SectionGuidelineMappings": [] + ] } ], "Checks": [ - "vm_backup_enabled", - "vm_sufficient_daily_backup_retention_period" + "app_function_not_publicly_accessible" ] }, { - "Id": "CCC.Core.CN03.AR01", - "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", + "Id": "CCC.SvlsComp.CN02.AR01", + "Description": "Send requests to invoke the function up to the allowed threshold and confirm they are successful; then send additional requests exceeding the threshold from the same entity and verify that they are denied.", "Attributes": [ { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "FamilyName": "Availability", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN02 Implement Function Invocation Rate Limits", "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "SubSectionObjective": "Ensure that function invocation is limited to a specified threshold from any single entity, preventing resource exhaustion and denial of service attacks.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_security_defaults_enabled", - "entra_user_with_vm_access_has_mfa" - ] - }, - { - "Id": "CCC.Core.CN03.AR02", - "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_security_defaults_enabled" - ] - }, - { - "Id": "CCC.Core.CN03.AR03", - "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_security_defaults_enabled" - ] - }, - { - "Id": "CCC.Core.CN03.AR04", - "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_user_with_vm_access_has_mfa" - ] - }, - { - "Id": "CCC.Core.CN05.AR01", - "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH12" ] } ], @@ -5366,782 +7670,19 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" + "PR.DS-4" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3" + "SC-5" ] } ] } ], - "Checks": [ - "aks_cluster_rbac_enabled", - "aks_network_policy_enabled", - "aks_clusters_public_access_disabled", - "app_client_certificates_on", - "app_ensure_auth_is_set_up", - "app_register_with_identity", - "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "app_function_not_publicly_accessible", - "app_function_access_keys_configured", - "iam_custom_role_has_permissions_to_administer_resource_locks", - "iam_subscription_roles_owner_custom_not_created", - "iam_role_user_access_admin_restricted", - "keyvault_rbac_enabled", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_global_admin_in_less_than_five_users", - "entra_non_privileged_user_has_mfa", - "entra_security_defaults_enabled", - "entra_trusted_named_locations_exists", - "entra_user_with_vm_access_has_mfa", - "vm_jit_access_enabled", - "vm_linux_enforce_ssh_authentication" - ] - }, - { - "Id": "CCC.Core.CN05.AR02", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "aks_cluster_rbac_enabled", - "app_register_with_identity", - "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "iam_custom_role_has_permissions_to_administer_resource_locks", - "iam_subscription_roles_owner_custom_not_created", - "iam_role_user_access_admin_restricted", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "containerregistry_admin_user_disabled", - "cosmosdb_account_use_private_endpoints", - "cosmosdb_account_firewall_use_selected_networks", - "cosmosdb_account_use_aad_and_rbac", - "keyvault_rbac_enabled", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "storage_account_key_access_disabled", - "storage_ensure_private_endpoints_in_storage_accounts", - "storage_ensure_azure_services_are_trusted_to_access_is_enabled", - "storage_default_to_entra_authorization_enabled", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted", - "aks_clusters_public_access_disabled", - "app_function_not_publicly_accessible", - "entra_global_admin_in_less_than_five_users", - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_trusted_named_locations_exists", - "entra_user_with_vm_access_has_mfa" - ] - }, - { - "Id": "CCC.Core.CN05.AR03", - "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_global_admin_in_less_than_five_users", - "entra_non_privileged_user_has_mfa", - "iam_role_user_access_admin_restricted", - "entra_trusted_named_locations_exists", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "keyvault_rbac_enabled", - "cosmosdb_account_firewall_use_selected_networks", - "cosmosdb_account_use_private_endpoints", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "containerregistry_admin_user_disabled", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted", - "app_function_not_publicly_accessible", - "storage_default_network_access_rule_is_denied", - "storage_ensure_private_endpoints_in_storage_accounts", - "storage_blob_public_access_level_is_disabled", - "storage_cross_tenant_replication_disabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR04", - "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "", - "SubSection": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "aks_cluster_rbac_enabled", - "aks_network_policy_enabled", - "aks_clusters_public_access_disabled", - "app_register_with_identity", - "app_function_access_keys_configured", - "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "app_ensure_auth_is_set_up", - "app_function_not_publicly_accessible", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "containerregistry_admin_user_disabled", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "keyvault_rbac_enabled", - "storage_account_key_access_disabled", - "storage_default_to_entra_authorization_enabled", - "storage_ensure_azure_services_are_trusted_to_access_is_enabled", - "storage_default_network_access_rule_is_denied", - "storage_secure_transfer_required_is_enabled", - "iam_role_user_access_admin_restricted", - "iam_subscription_roles_owner_custom_not_created", - "cosmosdb_account_use_aad_and_rbac", - "sqlserver_azuread_administrator_enabled", - "sqlserver_unrestricted_inbound_access", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted", - "vm_jit_access_enabled", - "entra_conditional_access_policy_require_mfa_for_management_api", - "entra_global_admin_in_less_than_five_users", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_trusted_named_locations_exists", - "entra_user_with_vm_access_has_mfa" - ] - }, - { - "Id": "CCC.Core.CN05.AR05", - "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "aks_clusters_created_with_private_nodes", - "aks_clusters_public_access_disabled", - "aks_network_policy_enabled", - "app_function_not_publicly_accessible", - "app_register_with_identity", - "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "app_client_certificates_on", - "app_ensure_auth_is_set_up", - "containerregistry_not_publicly_accessible", - "containerregistry_uses_private_link", - "containerregistry_admin_user_disabled", - "keyvault_private_endpoints", - "keyvault_access_only_through_private_endpoints", - "keyvault_rbac_enabled", - "keyvault_logging_enabled", - "storage_account_key_access_disabled", - "storage_default_to_entra_authorization_enabled", - "storage_ensure_private_endpoints_in_storage_accounts", - "storage_ensure_azure_services_are_trusted_to_access_is_enabled", - "iam_custom_role_has_permissions_to_administer_resource_locks", - "iam_role_user_access_admin_restricted", - "iam_subscription_roles_owner_custom_not_created", - "vm_jit_access_enabled", - "vm_linux_enforce_ssh_authentication", - "network_http_internet_access_restricted", - "network_rdp_internet_access_restricted", - "network_ssh_internet_access_restricted", - "network_udp_internet_access_restricted" - ] - }, - { - "Id": "CCC.Core.CN05.AR06", - "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "aks_cluster_rbac_enabled", - "app_register_with_identity", - "app_function_identity_is_configured", - "app_function_identity_without_admin_privileges", - "app_function_access_keys_configured", - "app_function_not_publicly_accessible", - "iam_custom_role_has_permissions_to_administer_resource_locks", - "iam_role_user_access_admin_restricted", - "iam_subscription_roles_owner_custom_not_created", - "cosmosdb_account_use_aad_and_rbac", - "entra_global_admin_in_less_than_five_users", - "entra_non_privileged_user_has_mfa", - "entra_privileged_user_has_mfa", - "entra_conditional_access_policy_require_mfa_for_management_api", - "keyvault_rbac_enabled", - "vm_jit_access_enabled", - "vm_linux_enforce_ssh_authentication" - ] - }, - { - "Id": "CCC.Core.CN04.AR01", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "keyvault_logging_enabled", - "network_flow_log_captured_sent", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_alert_create_update_sqlserver_fr", - "monitor_alert_delete_nsg", - "monitor_alert_delete_public_ip_address_rule", - "monitor_alert_delete_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_service_health_exists" - ] - }, - { - "Id": "CCC.Core.CN04.AR02", - "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "keyvault_logging_enabled", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "network_flow_log_captured_sent" - ] - }, - { - "Id": "CCC.Core.CN04.AR03", - "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "keyvault_logging_enabled", - "app_http_logs_enabled", - "network_flow_log_captured_sent", - "monitor_storage_account_with_activity_logs_is_private", - "monitor_storage_account_with_activity_logs_cmk_encrypted" - ] - }, - { - "Id": "CCC.Core.CN07.AR01", - "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "apim_threat_detection_llm_jacking" - ] - }, - { - "Id": "CCC.Core.CN07.AR02", - "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "monitor_diagnostic_settings_exists", - "monitor_diagnostic_setting_with_appropriate_categories", - "monitor_alert_create_update_sqlserver_fr", - "monitor_alert_delete_nsg", - "monitor_alert_delete_public_ip_address_rule", - "monitor_alert_delete_security_solution", - "monitor_alert_create_policy_assignment", - "monitor_alert_create_update_nsg", - "monitor_alert_create_update_public_ip_address_rule", - "monitor_alert_create_update_security_solution", - "monitor_alert_service_health_exists", - "monitor_storage_account_with_activity_logs_cmk_encrypted", - "monitor_storage_account_with_activity_logs_is_private" - ] + "Checks": [] } ] } diff --git a/prowler/compliance/gcp/ccc_gcp.json b/prowler/compliance/gcp/ccc_gcp.json index e3060646c5..df6b15bc5c 100644 --- a/prowler/compliance/gcp/ccc_gcp.json +++ b/prowler/compliance/gcp/ccc_gcp.json @@ -1,10 +1,1630 @@ { "Framework": "CCC", - "Version": "", + "Version": "v2025.10", "Provider": "GCP", "Name": "Common Cloud Controls Catalog (CCC)", "Description": "Common Cloud Controls Catalog (CCC) for GCP", "Requirements": [ + { + "Id": "CCC.Core.CN01.AR01", + "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "CCC.Core.CN01.AR02", + "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "compute_firewall_ssh_access_from_the_internet_allowed", + "compute_instance_block_project_wide_ssh_keys_disabled", + "compute_project_os_login_enabled", + "compute_project_os_login_2fa_enabled" + ] + }, + { + "Id": "CCC.Core.CN01.AR03", + "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_ssl_connections" + ] + }, + { + "Id": "CCC.Core.CN01.AR07", + "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN01.AR08", + "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "SubSection": "", + "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "IVS-03", + "IVS-07" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN13.AR01", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN13.AR02", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN13.AR03", + "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH18" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN06.AR01", + "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN06.AR02", + "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-19" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN08.AR01", + "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "CCC.Core.CN08.AR02", + "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "SubSection": "", + "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "BCR-08", + "BCR-10", + "BCR-11" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN09.AR01", + "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.Core.CN09.AR02", + "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "logging_sink_created", + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.Core.CN09.AR03", + "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07", + "CCC.Core.TH09", + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-02", + "LOG-04", + "LOG-09" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" + ] + }, + { + "Id": "CCC.Core.CN10.AR01", + "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", + "SubSection": "", + "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-10", + "DSP-19" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN02.AR01", + "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN02 Encrypt Data for Storage", + "SubSection": "", + "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-03", + "CEK-04", + "UEM-08", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_encryption_with_csek_enabled", + "dataproc_encrypted_with_cmks_disabled", + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption" + ] + }, + { + "Id": "CCC.Core.CN11.AR01", + "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN11.AR02", + "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR03", + "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "dataproc_encrypted_with_cmks_disabled", + "compute_instance_encryption_with_csek_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR04", + "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_key_not_publicly_accessible", + "iam_role_kms_enforce_separation_of_duties" + ] + }, + { + "Id": "CCC.Core.CN11.AR05", + "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-clear", + "tlp-green" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN11.AR06", + "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN11 Protect Encryption Keys", + "SubSection": "", + "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "CEK-08", + "CEK-10", + "CEK-12" + ] + } + ] + } + ], + "Checks": [ + "kms_key_rotation_enabled" + ] + }, + { + "Id": "CCC.Core.CN14.AR01", + "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups", + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_sufficient_retention_period" + ] + }, + { + "Id": "CCC.Core.CN14.AR02", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "CCC.Core.CN14.AR03", + "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.Core.CN14 Maintain Recent Backups", + "SubSection": "", + "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "CCC.Core.CN03.AR01", + "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "compute_project_os_login_2fa_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR02", + "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "apikeys_key_exists", + "apikeys_key_rotated_in_90_days" + ] + }, + { + "Id": "CCC.Core.CN03.AR03", + "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "compute_project_os_login_2fa_enabled" + ] + }, + { + "Id": "CCC.Core.CN03.AR04", + "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "SubSection": "", + "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-14" + ] + } + ] + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "apikeys_key_exists", + "apikeys_key_rotated_in_90_days" + ] + }, + { + "Id": "CCC.Core.CN05.AR01", + "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "compute_instance_public_ip", + "cloudsql_instance_public_ip", + "compute_instance_default_service_account_in_use", + "compute_instance_default_service_account_in_use_with_full_api_access", + "gke_cluster_no_default_service_account", + "iam_no_service_roles_at_project_level", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "CCC.Core.CN05.AR02", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "iam_no_service_roles_at_project_level", + "iam_sa_no_administrative_privileges", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_account_access_approval_enabled" + ] + }, + { + "Id": "CCC.Core.CN05.AR03", + "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_uses_vpc_service_controls" + ] + }, + { + "Id": "CCC.Core.CN05.AR04", + "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "cloudstorage_uses_vpc_service_controls", + "cloudsql_instance_public_ip", + "cloudsql_instance_public_access", + "compute_instance_public_ip", + "kms_key_not_publicly_accessible", + "bigquery_dataset_public_access" + ] + }, + { + "Id": "CCC.Core.CN05.AR05", + "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "compute_instance_public_ip", + "cloudstorage_bucket_public_access", + "cloudsql_instance_public_ip", + "kms_key_not_publicly_accessible", + "compute_image_not_publicly_shared", + "bigquery_dataset_public_access" + ] + }, + { + "Id": "CCC.Core.CN05.AR06", + "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", + "SubSection": "", + "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-01", + "DSP-07", + "DSP-08", + "DSP-10", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "iam_no_service_roles_at_project_level", + "iam_sa_no_administrative_privileges", + "iam_sa_no_user_managed_keys", + "iam_sa_user_managed_key_rotate_90_days", + "iam_sa_user_managed_key_unused", + "iam_service_account_unused", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties" + ] + }, + { + "Id": "CCC.Core.CN04.AR01", + "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", + "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", + "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", + "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" + ] + }, + { + "Id": "CCC.Core.CN04.AR02", + "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "cloudstorage_audit_logs_enabled", + "cloudstorage_bucket_logging_enabled", + "logging_sink_created" + ] + }, + { + "Id": "CCC.Core.CN04.AR03", + "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN04 Log All Access and Changes", + "SubSection": "", + "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-08" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "cloudstorage_audit_logs_enabled", + "cloudstorage_bucket_logging_enabled", + "logging_sink_created" + ] + }, + { + "Id": "CCC.Core.CN07.AR01", + "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Core.CN07.AR02", + "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements.", + "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH15" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "LOG-05", + "SEF-05" + ] + } + ] + } + ], + "Checks": [] + }, { "Id": "CCC.AuditLog.CN01.AR01", "Description": "When the signature validation process is performed, then it MUST detect any modification of data.", @@ -18,13 +1638,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure hash of data is included in digital signature. ", + "Recommendation": "Ensure hash of data is included in digital signature.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -44,12 +1664,7 @@ ] } ], - "Checks": [ - "iam_audit_logs_enabled", - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN01.AR02", @@ -64,13 +1679,13 @@ "Applicability": [ "tlp-red" ], - "Recommendation": "Ensure verification process includes a chained hash function. ", + "Recommendation": "Ensure verification process includes a chained hash function.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -90,11 +1705,7 @@ ] } ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN02.AR01", @@ -115,7 +1726,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -139,15 +1750,7 @@ ], "Checks": [ "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" + "logging_sink_created" ] }, { @@ -164,12 +1767,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -191,17 +1794,7 @@ } ], "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "iam_audit_logs_enabled" + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" ] }, { @@ -218,12 +1811,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Ensure alerting is correctly configured ", + "Recommendation": "Ensure alerting is correctly configured", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -245,9 +1838,7 @@ } ], "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created" + "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled" ] }, { @@ -264,13 +1855,13 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability. ", + "Recommendation": "Configure the audit log bucket to enable server access logging. Ensure the target logging bucket is configured for appropriate security, including restricted access and immutability.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01", - "CCC.TH09" + "CCC.Core.TH01", + "CCC.Core.TH09" ] } ], @@ -292,10 +1883,8 @@ } ], "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock", - "cloudstorage_bucket_public_access", - "cloudstorage_bucket_uniform_bucket_level_access", - "logging_sink_created" + "cloudstorage_bucket_logging_enabled", + "cloudstorage_audit_logs_enabled" ] }, { @@ -312,12 +1901,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure audit log exporting. ", + "Recommendation": "Configure audit log exporting.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -340,11 +1929,8 @@ } ], "Checks": [ - "logging_sink_created", "iam_audit_logs_enabled", - "cloudstorage_bucket_log_retention_policy_lock", - "cloudstorage_bucket_uniform_bucket_level_access", - "cloudstorage_bucket_public_access" + "logging_sink_created" ] }, { @@ -362,13 +1948,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period. ", + "Recommendation": "Configure the audit log bucket's lifecycle rules or object retention settings to enforce the required data retention period.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -390,8 +1976,7 @@ } ], "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created" + "cloudstorage_bucket_log_retention_policy_lock" ] }, { @@ -409,13 +1994,13 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket. ", + "Recommendation": "Enable MFA Delete (or equivalent multi-factor authentication for delete operations) on the audit log bucket.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06", - "CCC.TH07" + "CCC.Core.TH06", + "CCC.Core.TH07" ] } ], @@ -436,11 +2021,7 @@ ] } ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock", - "iam_audit_logs_enabled", - "logging_sink_created" - ] + "Checks": [] }, { "Id": "CCC.AuditLog.CN08.AR01", @@ -456,12 +2037,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure object lock policy. ", + "Recommendation": "Configure object lock policy.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -500,12 +2081,12 @@ "tlp-red", "tlp-amber" ], - "Recommendation": "Review field level access controls on audit data. ", + "Recommendation": "Review field level access controls on audit data.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH07" ] } ], @@ -547,59 +2128,12 @@ "tlp-amber", "tlp-green" ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_public_access", - "cloudstorage_bucket_uniform_bucket_level_access", - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.AuditLog.CN10.AR02", - "Description": "When the URL of a audit log storage bucket's object is accessed publicly then, it should be denied by bucket policy.", - "Attributes": [ - { - "FamilyName": "Confidentiality", - "FamilyDescription": "Controls designed to protected the confidentiality of Audit Log data.", - "Section": "CCC.AuditLog.CN10 Ensure Audit Bucket is Not Publicly Accessible", - "SubSection": "", - "SubSectionObjective": "Ensure that audit log storage buckets are not publicly accessible to prevent unauthorized exposure of sensitive log data.", - "Applicability": [ - "tlp-red", - "tlp-amber", - "tlp-green" - ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -626,25 +2160,26 @@ ] }, { - "Id": "CCC.Build.CN01.AR01", - "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", + "Id": "CCC.AuditLog.CN10.AR02", + "Description": "When the URL of a audit log storage bucket's object is accessed publicly then, it should be denied by bucket policy.", "Attributes": [ { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "", - "SubSection": "CCC.Build.C01 Restrict Allowed Build Agents", - "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", + "FamilyName": "Confidentiality", + "FamilyDescription": "Controls designed to protected the confidentiality of Audit Log data.", + "Section": "CCC.AuditLog.CN10 Ensure Audit Bucket is Not Publicly Accessible", + "SubSection": "", + "SubSectionObjective": "Ensure that audit log storage buckets are not publicly accessible to prevent unauthorized exposure of sensitive log data.", "Applicability": [ "tlp-red", - "tlp-amber" + "tlp-amber", + "tlp-green" ], - "Recommendation": "", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -652,14 +2187,296 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "AC-3", - "AC-6" + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "CCC.Logging.CN01.AR01", + "Description": "When a new cloud account is created, provider-level audit and network flow logging MUST be enabled by default and directed to the central sink.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", + "SubSection": "", + "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-2", + "AU-3" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "compute_subnet_flow_logs_enabled", + "logging_sink_created" + ] + }, + { + "Id": "CCC.Logging.CN01.AR02", + "Description": "When a new cloud compute resource is deployed, it MUST be configured to forward all relevant logs (e.g., OS, application, service logs) to the central log sink.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", + "SubSection": "", + "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-2", + "AU-3" + ] + } + ] + } + ], + "Checks": [ + "logging_sink_created", + "compute_subnet_flow_logs_enabled", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_enabled" + ] + }, + { + "Id": "CCC.Logging.CN02.AR01", + "Description": "When a new log bucket or stream is created, its retention policy MUST be configured in accordance with organisation's data retention policy.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "GV.PO-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_sufficient_retention_period" + ] + }, + { + "Id": "CCC.Logging.CN02.AR02", + "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", + "SubSection": "", + "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "GV.PO-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_sufficient_retention_period" + ] + }, + { + "Id": "CCC.Logging.CN03.AR01", + "Description": "When an attempt is made to modify or delete data before the object lock period expires, then the action MUST be denied.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data.", + "Section": "CCC.Logging.CN03 Enable Object Lock On Log Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure log immutability by enabling Write Once, Read Many (WORM) protection using object lock on log storage buckets. This prevents logs from being modified or deleted during the defined retention period, supporting compliance and forensic integrity.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "Configure object lock policy.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-9", + "AU-11" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.Logging.CN04.AR01", + "Description": "When restricted fields are accessed by unauthorized users, then those fields MUST remain masked.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN04 Restrict Field And Log Type Access", + "SubSection": "", + "SubSectionObjective": "Configure access to logs to follow the principle of least privilege in particular where technically possible limit the log fields users have access to to prevent accidental exposure to sensitive information such as PII.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "Review field level access controls on log data.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PS-04" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6", + "AU-9", + "AC-3", + "PT-2", + "PT-3", + "PT-3" ] } ] @@ -668,25 +2485,26 @@ "Checks": [] }, { - "Id": "CCC.Build.CN02.AR01", - "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", + "Id": "CCC.Logging.CN05.AR01", + "Description": "When a log storage bucket is created, the bucket's access control settings MUST explicitly deny public read and write access.", "Attributes": [ { - "FamilyName": "Access Control", - "FamilyDescription": "TODO: Describe this control family", - "Section": "", - "SubSection": "CCC.Build.C02 Restrict Allowed External Services for Build Triggers", - "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", + "SubSection": "", + "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", "Applicability": [ "tlp-red", - "tlp-amber" + "tlp-amber", + "tlp-green" ], - "Recommendation": "", + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -694,14 +2512,108 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "AC-3", - "AC-6" + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "CCC.Logging.CN05.AR02", + "Description": "When the URL of a log storage bucket's object is accessed publicly, the action MUST be denied by bucket policy.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify logs.", + "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", + "SubSection": "", + "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green" + ], + "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_public_access", + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "CCC.Logging.CN06.AR01", + "Description": "When a single principal executes an anomalously high number of log queries, an alert MUST be generated.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", + "Section": "CCC.Logging.CN06 Detect and Alert on Potential Log Exfiltration", + "SubSection": "", + "SubSectionObjective": "Identify and alert on anomalous data access patterns that may indicate an attempt to exfiltrate log data.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Logging.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "CA-7", + "AU-6" ] } ] @@ -710,26 +2622,1273 @@ "Checks": [] }, { - "Id": "CCC.Build.CN03.AR01", - "Description": "Attempt to access the build environment from an external network and verify that access is denied.", + "Id": "CCC.Logging.CN07.AR01", + "Description": "When an audit log event is recorded that corresponds to a modification of the logging service configuration such as disabling a log trail, deleting a log sink, or altering a log forwarding rule, an alert MUST be generated.", "Attributes": [ { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "", - "SubSection": "CCC.Build.C03 Deny External Network Access for Build Environments", - "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain logging-related events.", + "Section": "CCC.Logging.CN07 Detect and Alert on Log Service Tampering", + "SubSection": "", + "SubSectionObjective": "Alert when any component of the critical logging infrastructure is disabled, modified, or deleted, indicating a defense evasion attempt.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH02", - "CCC.TH05" + "CCC.Core.TH16" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "CA-7", + "AU-6" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled" + ] + }, + { + "Id": "CCC.Monitor.CN01.AR01", + "Description": "When an External Monitoring system exceeds the anticipated rate of monitoring checks then Rate Limiting MUST be applied and an Audit Alert MUST be generated.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", + "Section": "CCC.Monitor.CN01 Rate Limiting on External Monitoring", + "SubSection": "", + "SubSectionObjective": "Prevent DoS attacks using External Monitoring tools.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IR-01", + "DE.CM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-5", + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Monitor.CN02.AR01", + "Description": "When an Custom or User-Defined Metric starts to flood a collector, then a rate limit MUST be applied to reduce the network impact of traffic and an alert must triggered.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", + "Section": "CCC.Monitor.CN02 Rate Limiting on Metric Generation", + "SubSection": "", + "SubSectionObjective": "Prevent Malicious Actor or misconfiguration from flooding services with metric data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-5(2)", + "CA-7", + "SI-4" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Monitor.CN03.AR01", + "Description": "When external systems have approved access to internal systems not normally available for public access then they MUST be secured to prevent unauthorised access jumping through to the internal systems and only allow access to specific internal services.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN03 Access External Monitoring", + "SubSection": "", + "SubSectionObjective": "Control access to Synthetic monitoring solutions using API keys or Certificate based authentication to ensure they don't become an attack path, preventing monitoring systems from forging network requests to gain access to internal systems.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-06", + "PR.IR-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3" + ] + } + ] + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "apikeys_key_exists", + "apikeys_key_rotated_in_90_days" + ] + }, + { + "Id": "CCC.Monitor.CN04.AR01", + "Description": "When monitoring dashboards display degraded services which may become potential targets then the dashboard MUST be protected from unauthorised access.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN04 Restrict access to Monitoring Dashboards", + "SubSection": "", + "SubSectionObjective": "Control access to Monitoring Dashboards and reports to ensure they don't highlight an attack path.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-09", + "DE.AE-03" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "AC-3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Monitor.CN05.AR01", + "Description": "When monitoring services have generated an alert, the service MUST ensure only authorised responders silence or acknowledge the alert.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN05 Restrict access to silence or acknowledge an alert", + "SubSection": "", + "SubSectionObjective": "Ensure only a subset of users can silence or acknowledge alerts to prevent attackers hiding their activity.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IR-01", + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Monitor.CN06.AR01", + "Description": "When systems push metrics or traces they MUST be authenticated for that particular type of metric or trace", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", + "Section": "CCC.Monitor.CN06 Metrics pushed for authorised services only", + "SubSection": "", + "SubSectionObjective": "Use IAM to control which types of metrics or traces can be pushed by different system to avoid a compromised system pushing fabricated metrics about a different service", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Monitor.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-5" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_no_administrative_privileges", + "iam_sa_no_user_managed_keys", + "compute_instance_default_service_account_in_use", + "compute_instance_default_service_account_in_use_with_full_api_access" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR01", + "Description": "When a request is made to read a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR02", + "Description": "When a request is made to read an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR03", + "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN01.AR04", + "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", + "SubSection": "", + "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption, or sensitive data decryption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-03", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "kms_key_not_publicly_accessible" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR01", + "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_soft_delete_enabled", + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN03.AR02", + "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", + "SubSection": "", + "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR01", + "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_sufficient_retention_period", + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN04.AR02", + "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN04 Objects have an Effective Retention Policy by Default", + "SubSection": "", + "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + }, + { + "ReferenceId": "CCC.ObjStor", + "Identifiers": [ + "CCC.ObjStor.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_log_retention_policy_lock" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR01", + "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_versioning_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR02", + "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_versioning_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR03", + "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_versioning_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN05.AR04", + "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN05 Versioning is Enabled for All Objects in the Bucket", + "SubSection": "", + "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "DSP-17" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_versioning_enabled" + ] + }, + { + "Id": "CCC.ObjStor.CN07.AR01", + "Description": "The object storage service MUST support a configuration option that requires MFA to be successfully completed before any object deletion can be attempted, regardless of the request interface.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN07.AR02", + "Description": "When MFA deletion protection is enabled on a bucket or object namespace, the service MUST deny any deletion request from an identity that has not satisfied the MFA requirement at the time of the request.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN07.AR03", + "Description": "When an attempt is made to delete an object, the service's audit logs MUST clearly record each deletion attempt, including whether MFA was required and whether validation was met.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + "Section": "CCC.ObjStor.CN07 Multi-Factor Authentication Is Required for Object Deletion", + "SubSection": "", + "SubSectionObjective": "Ensure that deletion of objects stored in the object storage system is protected by multi-factor authentication (MFA), reducing the risk of accidental, unauthorized, or compromised-credentialโ€“based data destruction.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01", + "CCC.Core.TH06", + "CCC.Core.TH17" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "DSP-16", + "IAM-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.ObjStor.CN02.AR01", + "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", + "SubSection": "", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "CCC.ObjStor.CN02.AR02", + "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources.", + "Section": "CCC.ObjStor.CN02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", + "SubSection": "", + "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + } + ] + } + ], + "Checks": [ + "cloudstorage_bucket_uniform_bucket_level_access" + ] + }, + { + "Id": "CCC.LB.CN01.AR01", + "Description": "When a single client sends more than 2000 requests within any 5-minute sliding window, the load balancer MUST throttle all subsequent requests from that client for at least 60 seconds.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", + "SubSection": "", + "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH01", + "CCC.LB.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-1", + "PR.AC-7", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-6", + "SC-5", + "AC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN01.AR02", + "Description": "When throttling is invoked, the load balancer MUST record the event in the access log within 5 minutes for alerting and trend analysis.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", + "SubSection": "", + "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH01", + "CCC.LB.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-1", + "PR.AC-7", + "PR.PT-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-6", + "SC-5", + "AC-7" + ] + } + ] + } + ], + "Checks": [ + "compute_loadbalancer_logging_enabled" + ] + }, + { + "Id": "CCC.LB.CN06.AR01", + "Description": "When more than 10 percent of targets change from healthy to unhealthy within five minutes, an alert MUST be issued.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity.", + "Section": "CCC.LB.CN06 Secure Health-Check Telemetry", + "SubSection": "", + "SubSectionObjective": "Monitor health-check endpoints for tampering and alert on abnormal status changes.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.AE-2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4" + ] + } + ] + } + ], + "Checks": [ + "compute_loadbalancer_logging_enabled" + ] + }, + { + "Id": "CCC.LB.CN04.AR01", + "Description": "When routing weights change, the request MUST originate from an explicitly defined and trusted identity and MUST be logged.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN04 Enforce Distribution Policies", + "SubSection": "", + "SubSectionObjective": "Ensure traffic-splitting weights and algorithms are modified only by trusted identities.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3" + ] + } + ] + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "compute_loadbalancer_logging_enabled" + ] + }, + { + "Id": "CCC.LB.CN05.AR01", + "Description": "When stickiness is enabled, session cookies MUST expire within 30 minutes of inactivity.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN05 Validate Session Affinity", + "SubSection": "", + "SubSectionObjective": "Configure session persistence to minimise fixation and hijacking risks.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Audit CCC.LB.CP15 parameters via configuration scans.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-7" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-23" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN09.AR01", + "Description": "When an API call originates outside the approved CIDR set, the request MUST be denied.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can change or query load-balancer resources.", + "Section": "CCC.LB.CN09 Restrict Management API Access", + "SubSection": "", + "SubSectionObjective": "Limit load-balancer API calls to authorised identities and trusted networks.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Combine VPC endpoints with IAM condition-key filters for protected APIs.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH08" ] } ], @@ -743,102 +3902,7 @@ { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-7", - "SC-5" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "cloudstorage_bucket_public_access", - "cloudsql_instance_public_ip", - "cloudsql_instance_public_access" - ] - }, - { - "Id": "CCC.CntrReg.CN01.AR01", - "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", - "Attributes": [ - { - "FamilyName": "Risk Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", - "SubSection": "", - "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.CntrReg.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "ID.RA-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "RA-5", - "SI-5" - ] - } - ] - } - ], - "Checks": [ - "artifacts_container_analysis_enabled", - "gcr_container_scanning_enabled" - ] - }, - { - "Id": "CCC.DataWar.CN01.AR01", - "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", - "SubSection": "", - "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "AC-6" + "SC-7" ] } ] @@ -847,25 +3911,26 @@ "Checks": [] }, { - "Id": "CCC.DataWar.CN02.AR01", - "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", + "Id": "CCC.LB.CN02.AR01", + "Description": "When concurrent connections reach 80 percent of capacity, the autoscaling group MUST add at least one instance within five minutes.", "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", + "Section": "CCC.LB.CN02 Auto-Scale Load Balancer Capacity", "SubSection": "", - "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", + "SubSectionObjective": "Expand load-balancer capacity to maintain availability during traffic spikes.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-green", + "tlp-amber", + "tlp-red" ], - "Recommendation": "", + "Recommendation": "Enable autoscaling policies.", "SectionThreatMappings": [ { - "ReferenceId": "CCC", + "ReferenceId": "LB", "Identifiers": [ - "CCC.TH01" + "CCC.LB.TH09" ] } ], @@ -873,14 +3938,13 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "ID.BE-5" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3", - "AC-6" + "CP-10" ] } ] @@ -889,25 +3953,26 @@ "Checks": [] }, { - "Id": "CCC.DataWar.CN03.AR01", - "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", + "Id": "CCC.LB.CN07.AR01", + "Description": "When responses pass through the load balancer, the \"Server\" header MUST be replaced with \"lb\".", "Attributes": [ { "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", + "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer.", + "Section": "CCC.LB.CN07 Scrub Sensitive Headers", "SubSection": "", - "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", + "SubSectionObjective": "Remove headers that disclose internal details or software versions from HTTP responses.", "Applicability": [ - "tlp-red", - "tlp-amber" + "tlp-green", + "tlp-amber", + "tlp-red" ], - "Recommendation": "", + "Recommendation": "Configure header-transformation rules.", "SectionThreatMappings": [ { - "ReferenceId": "CCC", + "ReferenceId": "LB", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH15" ] } ], @@ -915,50 +3980,286 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-4" + "PR.DS-2" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-3", - "AC-6" + "SC-13" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.LB.CN08.AR01", + "Description": "When a certificate is within 30 days of expiry, automated renewal MUST complete and deploy a new certificate within 24 hours.", + "Attributes": [ + { + "FamilyName": "Encryption", + "FamilyDescription": "Controls that ensure trustworthy TLS certificates and ciphers.", + "Section": "CCC.LB.CN08 Automate Certificate Renewal", + "SubSection": "", + "SubSectionObjective": "Maintain valid TLS certificates by automating renewal and deployment before expiry.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "Use certificate-manager auto-renewal workflows.", + "SectionThreatMappings": [ + { + "ReferenceId": "LB", + "Identifiers": [ + "CCC.LB.TH07" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.DS-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-17" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.VPC.CN01.AR01", + "Description": "When a subscription is created, the subscription MUST NOT contain default network resources.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN01 Restrict Default Network Creation", + "SubSection": "", + "SubSectionObjective": "Restrict the automatic creation of default virtual networks and related resources during subscription initialization to avoid insecure default configurations and enforce custom network policies.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.3.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [ + "compute_network_default_in_use" + ] + }, + { + "Id": "CCC.VPC.CN02.AR01", + "Description": "When a resource is created in a public subnet, that resource MUST NOT be assigned an external IP address by default.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN02 Limit Resource Creation in Public Subnet", + "SubSection": "", + "SubSectionObjective": "Restrict the creation of resources in the public subnet with direct access to the internet to minimize attack surfaces.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-4" ] } ] } ], "Checks": [ - "iam_no_service_roles_at_project_level", - "iam_sa_no_administrative_privileges", - "iam_role_sa_enforce_separation_of_duties", - "iam_role_kms_enforce_separation_of_duties", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "cloudsql_instance_postgres_enable_pgaudit_flag", - "cloudsql_instance_postgres_log_connections_flag", - "cloudsql_instance_postgres_log_disconnections_flag", - "cloudsql_instance_postgres_log_min_messages_flag", - "cloudsql_instance_postgres_log_min_duration_statement_flag", - "cloudsql_instance_postgres_log_error_verbosity_flag", - "cloudsql_instance_postgres_log_min_error_statement_flag", - "cloudsql_instance_public_ip", - "cloudsql_instance_private_ip_assignment", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", "compute_instance_public_ip" ] }, + { + "Id": "CCC.VPC.CN03.AR01", + "Description": "When a VPC peering connection is requested, the service MUST prevent connections from VPCs that are not explicitly allowed.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN03 Restrict VPC Peering to Authorized Accounts", + "SubSection": "", + "SubSectionObjective": "Ensure VPC peering connections are only established with explicitly authorized destinations to limit network exposure and enforce boundary controls.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IVS-01" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.3" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.VPC.CN04.AR01", + "Description": "When any network traffic goes to or from an interface in the VPC, the service MUST capture and log all relevant information.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.VPC.CN04 Enforce VPC Flow Logs on VPCs", + "SubSection": "", + "SubSectionObjective": "Ensure VPCs are configured with flow logs enabled to capture traffic information.", + "Applicability": [ + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.VPC.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.PT-1" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.4.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AU-2" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IVS-06" + ] + } + ] + } + ], + "Checks": [ + "compute_subnet_flow_logs_enabled" + ] + }, { "Id": "CCC.KeyMgmt.CN01.AR01", "Description": "When a key version is scheduled for deletion or disabled, an alert MUST be generated within five minutes.", "Attributes": [ { - "FamilyName": "Logging and Metrics Publication", + "FamilyName": "Logging and Monitoring", "FamilyDescription": "Controls that collect, alert, and retain key-management events.", "Section": "CCC.KeyMgmt.CN01 Alert on Key-version Changes", "SubSection": "", @@ -1117,429 +4418,29 @@ ] } ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled" - ] - }, - { - "Id": "CCC.LB.CN01.AR01", - "Description": "When a single client sends more than 2000 requests within any 5-minute sliding window, the load balancer MUST throttle all subsequent requests from that client for at least 60 seconds.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", - "SubSection": "", - "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement per-IP token-bucket limits with and verify via synthetic traffic tests. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH01", - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-1", - "PR.AC-7", - "PR.PT-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6", - "SC-5", - "AC-7" - ] - } - ] - } - ], - "Checks": [ - "compute_loadbalancer_logging_enabled", - "compute_subnet_flow_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" - ] - }, - { - "Id": "CCC.LB.CN01.AR02", - "Description": "When throttling is invoked, the load balancer MUST record the event in the access log within 5 minutes for alerting and trend analysis.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN01 Enforce and Detect Rate Limiting", - "SubSection": "", - "SubSectionObjective": "Detect and throttle malicious or excessive requests to prevent downstream resource exhaustion and brute-force activity.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Enable access logging and configure metric filters on HTTP 429 counts to trigger alerts. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH01", - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-1", - "PR.AC-7", - "PR.PT-4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6", - "SC-5", - "AC-7" - ] - } - ] - } - ], - "Checks": [ - "compute_loadbalancer_logging_enabled", - "logging_sink_created" - ] - }, - { - "Id": "CCC.LB.CN06.AR01", - "Description": "When more than 10 percent of targets change from healthy to unhealthy within five minutes, an alert MUST be issued.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that detect anomalous traffic and record load-balancer activity. ", - "Section": "CCC.LB.CN06 Secure Health-Check Telemetry", - "SubSection": "", - "SubSectionObjective": "Monitor health-check endpoints for tampering and alert on abnormal status changes.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Instrument metrics for health check results and target removal events. Configure monitoring alarms to alert on abnormal spikes in unhealthy targets. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4" - ] - } - ] - } - ], - "Checks": [ - "compute_loadbalancer_logging_enabled", - "logging_sink_created", - "compute_subnet_flow_logs_enabled" - ] - }, - { - "Id": "CCC.LB.CN04.AR01", - "Description": "When routing weights change, the request MUST originate from an explicitly defined and trusted identity and MUST be logged.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN04 Enforce Distribution Policies", - "SubSection": "", - "SubSectionObjective": "Ensure traffic-splitting weights and algorithms are modified only by trusted identities.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Define a list of trusted principals allowed to modify routing configurations. Enforce via conditional access policies, and log changes using audit logging. ", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "compute_loadbalancer_logging_enabled", - "logging_sink_created", - "iam_no_service_roles_at_project_level", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges" - ] - }, - { - "Id": "CCC.LB.CN05.AR01", - "Description": "When stickiness is enabled, session cookies MUST expire within 30 minutes of inactivity.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN05 Validate Session Affinity", - "SubSection": "", - "SubSectionObjective": "Configure session persistence to minimise fixation and hijacking risks.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Audit CCC.LB.F15 parameters via configuration scans.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-23" - ] - } - ] - } - ], - "Checks": [ - "iam_no_service_roles_at_project_level", - "iam_sa_no_administrative_privileges", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.LB.CN09.AR01", - "Description": "When an API call originates outside the approved CIDR set, the request MUST be denied.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can change or query load-balancer resources. ", - "Section": "CCC.LB.CN09 Restrict Management API Access", - "SubSection": "", - "SubSectionObjective": "Limit load-balancer API calls to authorised identities and trusted networks.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Combine VPC endpoints with IAM condition-key filters for protected APIs.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH08" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_no_service_roles_at_project_level", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled" - ] - }, - { - "Id": "CCC.LB.CN02.AR01", - "Description": "When concurrent connections reach 80 percent of capacity, the autoscaling group MUST add at least one instance within five minutes.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", - "Section": "CCC.LB.CN02 Auto-Scale Load Balancer Capacity", - "SubSection": "", - "SubSectionObjective": "Expand load-balancer capacity to maintain availability during traffic spikes.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Enable autoscaling policies.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "ID.BE-5" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-10" - ] - } - ] - } - ], "Checks": [] }, { - "Id": "CCC.LB.CN07.AR01", - "Description": "When responses pass through the load balancer, the \"Server\" header MUST be replaced with \"lb\".", + "Id": "CCC.SecMgmt.CN01.AR01", + "Description": "Attempt to use an outdated version of a secret after its rotation period has passed and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "Controls that preserve availability and confidentiality of traffic processed by the load balancer. ", - "Section": "CCC.LB.CN07 Scrub Sensitive Headers", + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN01 Enforce Automatic Secret Rotation", "SubSection": "", - "SubSectionObjective": "Remove headers that disclose internal details or software versions from HTTP responses.", + "SubSectionObjective": "Ensure that secrets are automatically rotated on a defined schedule to reduce the risk of secret compromise and unauthorized access.", "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], - "Recommendation": "Configure header-transformation rules.", + "Recommendation": "", "SectionThreatMappings": [ { - "ReferenceId": "LB", + "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-13" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.LB.CN08.AR01", - "Description": "When a certificate is within 30 days of expiry, automated renewal MUST complete and deploy a new certificate within 24 hours.", - "Attributes": [ - { - "FamilyName": "Encryption", - "FamilyDescription": "Controls that ensure trustworthy TLS certificates and ciphers.", - "Section": "CCC.LB.CN08 Automate Certificate Renewal", - "SubSection": "", - "SubSectionObjective": "Maintain valid TLS certificates by automating renewal and deployment before expiry.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use certificate-manager auto-renewal workflows.", - "SectionThreatMappings": [ - { - "ReferenceId": "LB", - "Identifiers": [ - "CCC.LB.TH07" + "CCC.Core.TH01", + "CCC.Core.TH14" ] } ], @@ -1553,7 +4454,8 @@ { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-17" + "SC-12", + "SC-28" ] } ] @@ -1562,214 +4464,26 @@ "Checks": [] }, { - "Id": "CCC.Logging.CN01.AR01", - "Description": "When a new cloud account is created, provider-level audit and network flow logging MUST be enabled by default and directed to the central sink.", + "Id": "CCC.SecMgmt.CN02.AR01", + "Description": "Attempt to retrieve a secret from an unauthorized region and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SecMgmt.CN02 Enforce Secret Replication Policies", "SubSection": "", - "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "compute_subnet_flow_logs_enabled", - "logging_sink_created" - ] - }, - { - "Id": "CCC.Logging.CN01.AR02", - "Description": "When a new cloud compute resource is deployed, it MUST be configured to forward all relevant logs (e.g., OS, application, service logs) to the central log sink.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN01 Centralized and Comprehensive Log Aggregation", - "SubSection": "", - "SubSectionObjective": "Ensure all operational and security logs from across the cloud environment, including applications, operating systems, network traffic, and cloud service activity, are captured automatically and streamed to a central, secure log management service.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH07" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3" - ] - } - ] - } - ], - "Checks": [ - "logging_sink_created", - "cloudstorage_bucket_log_retention_policy_lock", - "iam_audit_logs_enabled", - "compute_subnet_flow_logs_enabled", - "compute_network_dns_logging_enabled", - "compute_loadbalancer_logging_enabled" - ] - }, - { - "Id": "CCC.Logging.CN02.AR01", - "Description": "When a new log bucket or stream is created, its retention policy MUST be configured in accordance with organisation's data retention policy.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "GV.PO-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.Logging.CN02.AR02", - "Description": "When a query is performed to retrieve log events older than the number of days defined in the organisation's data retention policy, it MUST return an empty result.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN02 Enforce Data Retention Policy for Logs", - "SubSection": "", - "SubSectionObjective": "Ensure that the retention period configured for logs aligns with the organization's data retention policy.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "GV.PO-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.AuditLog.CN08.AR01", - "Description": "When an attempt is made to modify or delete data before the object lock period expires, then the action MUST be denied.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "Controls related to the confidentiality, integrity and availability of log data. ", - "Section": "CCC.Logging.CN03 Enable Object Lock On Log Bucket", - "SubSection": "", - "SubSectionObjective": "Ensure log immutability by enabling Write Once, Read Many (WORM) protection using object lock on log storage buckets. This prevents logs from being modified or deleted during the defined retention period, supporting compliance and forensic integrity.", + "SubSectionObjective": "Ensure that secrets are replicated only to authorized locations as per organizational data residency and compliance requirements.", "Applicability": [ "tlp-red", "tlp-amber" ], - "Recommendation": "Configure object lock policy. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07" + "CCC.Core.TH03", + "CCC.Core.TH04" ] } ], @@ -1777,98 +4491,7 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9", - "AU-11" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.AuditLog.CN04.AR01", - "Description": "When restricted fields are accessed by unauthorized users, then those fields MUST remain masked.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN04 Restrict Field And Log Type Access", - "SubSection": "", - "SubSectionObjective": "Configure access to logs to follow the principle of least privilege in particular where technically possible limit the log fields users have access to to prevent accidental exposure to sensitive information such as PII.", - "Applicability": [ - "tlp-red", - "tlp-amber" - ], - "Recommendation": "Review field level access controls on log data. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Logging.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PS-04" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-6", - "AU-9", - "AC-3", - "PT-2", - "PT-3", - "PT-3" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.Logging.CN05.AR01", - "Description": "When a log storage bucket is created, the bucket's access control settings MUST explicitly deny public read and write access.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", - "SubSection": "", - "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", - "Applicability": [ - "tlp-red", - "tlp-amber", - "tlp-green" - ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" + "PR.DS-5" ] }, { @@ -1881,946 +4504,28 @@ ] } ], - "Checks": [ - "cloudstorage_bucket_public_access", - "cloudstorage_bucket_uniform_bucket_level_access", - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created" - ] + "Checks": [] }, { - "Id": "CCC.Logging.CN05.AR02", - "Description": "When the URL of a log storage bucket's object is accessed publicly, the action MUST be denied by bucket policy.", + "Id": "CCC.DataWar.CN01.AR01", + "Description": "Attempt to access underlying database tables directly without using managed views and verify that access is denied.", "Attributes": [ { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls that restrict who can access and modify logs. ", - "Section": "CCC.Logging.CN05 Ensure Log Bucket is Not Publicly Accessible", + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN01 Enforce Use of Managed Views for Data Access", "SubSection": "", - "SubSectionObjective": "Ensure that log storage buckets are not publicly accessible to prevent unauthorized access to sensitive log data. In addition, logs should be replicated to another cloud region to enhance availability, durability, and support disaster recovery requirements.", + "SubSectionObjective": "Ensure that data access is provided through managed views, restricting users from accessing underlying tables directly and enforcing consistent security policies.", "Applicability": [ "tlp-red", - "tlp-amber", - "tlp-green" - ], - "Recommendation": "Configure bucket policies and access control lists (ACLs) to restrict public access. Regularly review bucket permissions to ensure no public access has been inadvertently granted. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_public_access", - "cloudstorage_bucket_uniform_bucket_level_access" - ] - }, - { - "Id": "CCC.Logging.CN06.AR01", - "Description": "When a single principal executes an anomalously high number of log queries, an alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", - "Section": "CCC.Logging.CN06 Detect and Alert on Potential Log Exfiltration", - "SubSection": "", - "SubSectionObjective": "Identify and alert on anomalous data access patterns that may indicate an attempt to exfiltrate log data.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.Logging.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-03", - "DE.CM-09" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "CA-7", - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_sink_created" - ] - }, - { - "Id": "CCC.Logging.CN07.AR01", - "Description": "When an audit log event is recorded that corresponds to a modification of the logging service configuration such as disabling a log trail, deleting a log sink, or altering a log forwarding rule, an alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging and Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain logging-related events. ", - "Section": "CCC.Logging.CN07 Detect and Alert on Log Service Tampering", - "SubSection": "", - "SubSectionObjective": "Alert when any component of the critical logging infrastructure is disabled, modified, or deleted, indicating a defense evasion attempt.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-03", - "DE.CM-09" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "CA-7", - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR01", - "Description": "When a request is made to read a protected bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR02", - "Description": "When a request is made to read a protected object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.ObjStor.CN01.AR03", - "Description": "When a request is made to write to a bucket, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption", - "dataproc_encrypted_with_cmks_disabled" - ] - }, - { - "Id": "CCC.ObjStor.CN01.AR04", - "Description": "When a request is made to write to an object, the service MUST prevent any request using KMS keys not listed as trusted by the organization.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN01 Prevent Unencrypted Requests", - "SubSection": "CCC.ObjStor.C01 Prevent Requests to Buckets or Objects with Untrusted KMS Keys", - "SubSectionObjective": "Prevent any requests to object storage buckets or objects using untrusted KMS keys to protect against unauthorized data encryption that can impact data availability and integrity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01", - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-04", - "DCS-06" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled", - "dataproc_encrypted_with_cmks_disabled", - "compute_instance_encryption_with_csek_enabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR01", - "Description": "When an object storage bucket deletion is attempted, the bucket MUST be fully recoverable for a set time-frame after deletion is requested.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN03.AR02", - "Description": "When an attempt is made to modify the retention policy for an object storage bucket, the service MUST prevent the policy from being modified.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "CCC.ObjStor.C03 Prevent Bucket Deletion Through Irrevocable Bucket Retention Policy", - "SubSectionObjective": "Ensure that object storage bucket is not deleted after creation, and that the preventative measure cannot be unset.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN04.AR01", - "Description": "When an object is uploaded to the object storage system, the object MUST automatically receive a default retention policy that prevents premature deletion or modification.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN04.AR02", - "Description": "When an attempt is made to delete or modify an object that is subject to an active retention policy, the service MUST prevent the action from being completed.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN04 Log All Access and Changes", - "SubSection": "CCC.ObjStor.C04 Objects have an Effective Retention Policy by Default", - "SubSectionObjective": "Ensure that all objects stored in the object storage system have a retention policy applied by default, preventing premature deletion or modification of objects and ensuring compliance with data retention regulations.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.ObjStor.CN05.AR01", - "Description": "When an object is uploaded to the object storage bucket, the object MUST be stored with a unique identifier.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.ObjStor.CN05.AR02", - "Description": "When an object is modified, the service MUST assign a new unique identifier to the modified object to differentiate it from the previous version.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.ObjStor.CN05.AR03", - "Description": "When an object is modified, the service MUST allow for recovery of previous versions of the object.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.ObjStor.CN05.AR04", - "Description": "When an object is deleted, the service MUST retain other versions of the object to allow for recovery of previous versions.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN05 Prevent Access from Untrusted Entities", - "SubSection": "CCC.ObjStor.C05 Versioning is Enabled for All Objects in the Bucket", - "SubSectionObjective": "Ensure that versioning is enabled for all objects stored in the object storage bucket to enable recovery of previous versions of objects in case of loss or corruption.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.1.4" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-28", - "CP-10" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-16" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.ObjStor.CN06.AR01", - "Description": "When an object storage bucket is accessed, the service MUST store access logs in a separate data store.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN06 Prevent Deployment in Restricted Regions", - "SubSection": "CCC.ObjStor.C06 Access Logs are Stored in a Separate Data Store", - "SubSectionObjective": "Ensure that access logs for object storage buckets are stored in a separate data store to protect against unauthorized access, tampering, or deletion of logs (Logbuckets are exempt from this requirement, but must be tlp-red).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH07", - "CCC.TH09" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-6" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-07", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2022 A.8.15.0" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock", - "logging_sink_created" - ] - }, - { - "Id": "CCC.ObjStor.CN02.AR01", - "Description": "When a permission set is allowed for an object in a bucket, the service MUST allow the same permission set to access all objects in the same bucket.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -2831,54 +4536,38 @@ "PR.AC-4" ] }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.1" - ] - }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "AC-3", "AC-6" ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] } ] } ], - "Checks": [ - "cloudstorage_bucket_uniform_bucket_level_access" - ] + "Checks": [] }, { - "Id": "CCC.ObjStor.CN02.AR02", - "Description": "When a permission set is denied for an object in a bucket, the service MUST deny the same permission set to access all objects in the same bucket.", + "Id": "CCC.DataWar.CN02.AR01", + "Description": "Attempt to query sensitive columns without the necessary permissions and verify that access is denied or data is masked.", "Attributes": [ { - "FamilyName": "Identity and Access Management", + "FamilyName": "Data", "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.CN02 Ensure Data Encryption at Rest for All Stored Data", - "SubSection": "CCC.ObjStor.C02 Enforce Uniform Bucket-level Access to Prevent Inconsistent Permissions", - "SubSectionObjective": "Ensure that uniform bucket-level access is enforced across all object storage buckets. This prevents the use of ad-hoc or inconsistent object-level permissions, ensuring centralized, consistent, and secure access management in accordance with the principle of least privilege.", + "Section": "CCC.DataWar.CN02 Enforce Column-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to sensitive data columns is restricted based on user roles, preventing unauthorized access to sensitive information.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -2890,9 +4579,45 @@ ] }, { - "ReferenceId": "ISO_27001", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "2013 A.9.4.1" + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.DataWar.CN03.AR01", + "Description": "Attempt to query data rows that the user should not have access to and verify that access is denied or data is not returned.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.DataWar.CN03 Enforce Row-Level Security Policies", + "SubSection": "", + "SubSectionObjective": "Ensure that access to data rows is restricted based on user roles or attributes, preventing unauthorized access to specific subsets of data.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" ] }, { @@ -2901,502 +4626,12 @@ "AC-3", "AC-6" ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DCS-09" - ] - } - ] - } - ], - "Checks": [ - "cloudstorage_bucket_uniform_bucket_level_access" - ] - }, - { - "Id": "CCC.Monitor.CN01.AR01", - "Description": "When an External Monitoring system exceeds the anticipated rate of monitoring checks then Rate Limiting MUST be applied and an Audit Alert MUST be generated.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", - "Section": "CCC.Monitor.CN01 Rate Limiting on External Monitoring", - "SubSection": "", - "SubSectionObjective": "Prevent DoS attacks using External Monitoring tools.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.IR-01", - "DE.CM-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-5", - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_sink_created", - "cloudstorage_bucket_log_retention_policy_lock", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.Monitor.CN02.AR01", - "Description": "When an Custom or User-Defined Metric starts to flood a collector, then a rate limit MUST be applied to reduce the network impact of traffic and an alert must triggered.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "Controls that collect, alert, and retain events from other monitoring services.", - "Section": "CCC.Monitor.CN02 Rate Limiting on Metric Generation", - "SubSection": "", - "SubSectionObjective": "Prevent Malicious Actor or misconfiguration from flooding services with metric data.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-01" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-5(2)", - "CA-7", - "SI-4" - ] - } - ] - } - ], - "Checks": [ - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "iam_audit_logs_enabled", - "compute_loadbalancer_logging_enabled", - "compute_network_dns_logging_enabled", - "compute_subnet_flow_logs_enabled" - ] - }, - { - "Id": "CCC.Monitor.CN03.AR01", - "Description": "When external systems have approved access to internal systems not normally available for public access then they MUST be secured to prevent unauthorised access jumping through to the internal systems and only allow access to specific internal services.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN03 Access External Monitoring", - "SubSection": "", - "SubSectionObjective": "Control access to Synthetic monitoring solutions using API keys or Certificate based authentication to ensure they don't become an attack path, preventing monitoring systems from forging network requests to gain access to internal systems.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-06", - "PR.IR-01", - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "apikeys_api_restrictions_configured", - "apikeys_key_exists", - "apikeys_key_rotated_in_90_days" - ] - }, - { - "Id": "CCC.Monitor.CN04.AR01", - "Description": "When monitoring dashboards display degraded services which may become potential targets then the dashboard MUST be protected from unauthorised access.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN04 Restrict access to Monitoring Dashboards", - "SubSection": "", - "SubSectionObjective": "Control access to Monitoring Dashboards and reports to ensure they don't highlight an attack path.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.CM-09", - "DE.AE-03" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SI-4", - "AC-3" - ] } ] } ], "Checks": [] }, - { - "Id": "CCC.Monitor.CN05.AR01", - "Description": "When monitoring services have generated an alert, the service MUST ensure only authorised responders silence or acknowledge the alert.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN05 Restrict access to silence or acknowledge an alert", - "SubSection": "", - "SubSectionObjective": "Ensure only a subset of users can silence or acknowledge alerts to prevent attackers hiding their activity.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH10" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.IR-01", - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_sink_created", - "iam_organization_essential_contacts_configured" - ] - }, - { - "Id": "CCC.Monitor.CN06.AR01", - "Description": "When systems push metrics or traces they MUST be authenticated for that particular type of metric or trace", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "Controls designed to prevent unauthorised access to monitoring features.", - "Section": "CCC.Monitor.CN06 Metrics pushed for authorised services only", - "SubSection": "", - "SubSectionObjective": "Use IAM to control which types of metrics or traces can be pushed by different system to avoid a compromised system pushing fabricated metrics about a different service", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.Monitor.TH05" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AA-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-5" - ] - } - ] - } - ], - "Checks": [ - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "gke_cluster_no_default_service_account", - "iam_no_service_roles_at_project_level", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused" - ] - }, - { - "Id": "CCC.VPC.CN01.AR01", - "Description": "When a subscription is created, the subscription MUST NOT contain default network resources.", - "Attributes": [ - { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.VPC.CN01 Restrict Default Network Creation", - "SubSection": "", - "SubSectionObjective": "Restrict the automatic creation of default virtual networks and related resources during subscription initialization to avoid insecure default configurations and enforce custom network policies.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.VPC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "TVM-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.12.3.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-7" - ] - } - ] - } - ], - "Checks": [ - "compute_network_default_in_use" - ] - }, - { - "Id": "CCC.VPC.CN03.AR01", - "Description": "When a VPC peering connection is requested, the service MUST prevent connections from VPCs that are not explicitly allowed.", - "Attributes": [ - { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.VPC.CN03 Restrict VPC Peering to Authorized Accounts", - "SubSection": "", - "SubSectionObjective": "Ensure VPC peering connections are only established with explicitly authorized destinations to limit network exposure and enforce boundary controls.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.VPC.TH03" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IVS-01" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-4" - ] - } - ] - } - ], - "Checks": [] - }, - { - "Id": "CCC.VPC.CN04.AR01", - "Description": "When any network traffic goes to or from an interface in the VPC, the service MUST capture and log all relevant information.", - "Attributes": [ - { - "FamilyName": "Network Security", - "FamilyDescription": "TODO: Describe this control family", - "Section": "CCC.VPC.CN04 Enforce VPC Flow Logs on VPCs", - "SubSection": "", - "SubSectionObjective": "Ensure VPCs are configured with flow logs enabled to capture traffic information.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.VPC.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PT-1" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.12.4.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IVS-06" - ] - } - ] - } - ], - "Checks": [ - "compute_subnet_flow_logs_enabled" - ] - }, { "Id": "CCC.Vector.CN01.AR01", "Description": "When a vector embedding is submitted for indexing, the system MUST validate that it matches expected schema, dimension, and format profiles.", @@ -3420,7 +4655,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH05", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3459,7 +4694,7 @@ "Identifiers": [ "CCC.Vector.TH02", "CCC.Vector.TH04", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3474,11 +4709,7 @@ } ], "Checks": [ - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "iam_no_service_roles_at_project_level", - "kms_key_not_publicly_accessible" + "iam_sa_no_administrative_privileges" ] }, { @@ -3501,7 +4732,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH03", - "CCC.TH01" + "CCC.Core.TH01" ] } ], @@ -3540,7 +4771,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH02", - "CCC.TH12" + "CCC.Core.TH12" ] } ], @@ -3576,8 +4807,8 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH04", - "CCC.TH09", - "CCC.TH04" + "CCC.Core.TH09", + "CCC.Core.TH04" ] } ], @@ -3591,18 +4822,7 @@ ] } ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled" - ] + "Checks": [] }, { "Id": "CCC.Vector.CN06.AR01", @@ -3626,7 +4846,7 @@ "ReferenceId": "CCC", "Identifiers": [ "CCC.Vector.TH05", - "CCC.TH06" + "CCC.Core.TH06" ] } ], @@ -3671,422 +4891,25 @@ "Checks": [] }, { - "Id": "CCC.Core.CN01.AR01", - "Description": "When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + "Id": "CCC.RDMS.CN01.AR02", + "Description": "When an attempt is made to authenticate to the database using known default credentials, the authentication attempt must fail and no access should be granted.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN01 Password Management", "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Most cloud services enable TLS 1.3 by default. Where it is not already set, ensure that your services are configured or updated accordingly. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudsql_instance_ssl_connections" - ] - }, - { - "Id": "CCC.Core.CN01.AR02", - "Description": "When a port is exposed for SSH network traffic, all traffic MUST include a SSH handshake AND be encrypted using SSHv2 or higher.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Any time port 22 is exposed, ensure that it has a properly implemented SSH server with SSHv2 enabled and configured with strong ciphers. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_ssh_access_from_the_internet_allowed" - ] - }, - { - "Id": "CCC.Core.CN01.AR03", - "Description": "When the service receives unencrypted traffic, then it MUST either block the request or automatically redirect it to the secure equivalent.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Review firewall, load balancer, and application configurations to ensure insecure protocols such as HTTP, FTP, and Telnet are not exposed. Where possible, implement automatic redirection to secure protocols such as HTTPS, SFTP, SSH, and regularly scan for protocol drift. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudsql_instance_ssl_connections", - "cloudsql_instance_public_access", - "cloudsql_instance_public_ip", - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "cloudstorage_bucket_public_access" - ] - }, - { - "Id": "CCC.Core.CN01.AR07", - "Description": "When a port is exposed, the service MUST ensure that the protocol and service officially assigned to that port number by the IANA Service Name and Transport Protocol Port Number Registry, and no other, is run on that port.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Reference the IANA Service Name and Transport Protocol Port Number Registry for more information about correct protocol-to-port assignments. Avoid running non-standard services on well-known ports. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed" - ] - }, - { - "Id": "CCC.Core.CN01.AR08", - "Description": "When a service transmits data using TLS, mutual TLS (mTLS) MUST be implemented to require both client and server certificate authentication for all connections.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN01 Encrypt Data for Transmission", - "SubSection": "", - "SubSectionObjective": "Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Configure mTLS for all endpoints that process or transmit sensitive data. Ensure both client and server certificates are validated and managed securely. Regularly review certificate authorities and automate certificate rotation where possible. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH02" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-03", - "CEK-04", - "IVS-03", - "IVS-07" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-02" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.1" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-8", - "SC-13" - ] - } - ] - } - ], - "Checks": [ - "cloudsql_instance_ssl_connections" - ] - }, - { - "Id": "CCC.Core.CN13.AR01", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST only use valid, unexpired certificates issued by a trusted certificate authority.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [] - }, - { - "Id": "CCC.Core.CN13.AR02", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 180 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", + "SubSectionObjective": "Ensure default vendor-supplied DB administrator credentials are replaced with strong, unique passwords and that these credentials are properly managed using a secure password or secrets management solution.", "Applicability": [ + "tlp-red", "tlp-amber" ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [] - }, - { - "Id": "CCC.Core.CN13.AR03", - "Description": "When a port is exposed that uses certificate-based encryption, the service MUST rotate active certificates within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN13 Minimize Lifetime of Encryption and Authentication Certificates", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption and authentication certificates have a limited lifetime to reduce the risk of compromise and ensure the use of up-to-date security practices.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Track certificate expiration dates and automate certificate renewal where possible. Use certificate management tools to ensure only certificates from trusted authorities are deployed. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH18" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "apikeys_key_rotated_in_90_days", - "kms_key_rotation_enabled" - ] - }, - { - "Id": "CCC.Core.CN06.AR01", - "Description": "When the service is running, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", - "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate the service's deployment location is included in this list. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH01" ] } ], @@ -4094,19 +4917,89 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.AA-01" ] }, { - "ReferenceId": "CCM", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "DSP-19" + "AC-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN02.AR01", + "Description": "When repeated failed login attempts are made in a short timeframe, the account must be locked out or rate-limited to prevent further login attempts.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN02 Account Lockout and Rate-Limiting", + "SubSection": "", + "SubSectionObjective": "Ensure the database enforces lockouts or rate-limiting after a specified number of failed authentication attempts. This prevents brute force or password-guessing attacks from succeeding.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-1" ] }, { - "ReferenceId": "ISO_27001", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "2013 A.11.1.1" + "AC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.RDMS.CN04.AR01", + "Description": "When there is an attempt to perform a backup or restore, then the attempt must fail with an access denied message if credentials or roles that are not explicitly authorized for backup/restore functions.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN04 Access Control for Backup and Restore Operations", + "SubSection": "", + "SubSectionObjective": "Restrict who can initiate, manage, and validate database backup or restore operations through strict role-based or least-privilege access. Prevents accidental or malicious restorations, protecting data integrity and availability.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" ] }, { @@ -4118,30 +5011,30 @@ ] } ], - "Checks": [] + "Checks": [ + "iam_no_service_roles_at_project_level" + ] }, { - "Id": "CCC.Core.CN06.AR02", - "Description": "When a child resource is deployed, its region and availability zone MUST be included in a list of explicitly trusted or approved locations within the trust perimeter.", + "Id": "CCC.RDMS.CN05.AR01", + "Description": "When an attempt is made to share a snapshot with an unauthorized account, the sharing request must be denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN06 Restrict Deployments to Trust Perimeter", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN05 Restrict Snapshot Sharing to Authorized Accounts", "SubSection": "", - "SubSectionObjective": "Ensure that the service and its child resources are only deployed on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Ensure database snapshots can only be shared with explicitly authorized accounts, thereby minimizing the risk of data exposure or exfiltration.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], - "Recommendation": "Maintain an up-to-date list of trusted and approved regions based on organizational policies. Validate that child resources can only be deployed to locations included in this list. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH03" + "CCC.RDMS.TH05" ] } ], @@ -4149,24 +5042,99 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-19" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.11.1.1" + "PR.DS-10" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ + "AC-4" + ] + } + ] + } + ], + "Checks": [ + "compute_image_not_publicly_shared" + ] + }, + { + "Id": "CCC.RDMS.CN03.AR01", + "Description": "When backups are disabled, paused, or fail to run as scheduled, an alert must be triggered and logged.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.RDMS.CN03 Enforce and Monitor Automated Backups", + "SubSection": "", + "SubSectionObjective": "Ensure database backups are automatically scheduled, actively monitored, and promptly reported if any disruptions occur. This helps maintain data integrity, facilitates disaster recovery, and supports business continuity when a system failure or breach occurs.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.RDMS.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "CP-9" + ] + } + ] + } + ], + "Checks": [ + "cloudsql_instance_automated_backups" + ] + }, + { + "Id": "CCC.Build.CN01.AR01", + "Description": "Attempt to initiate a build using an unauthorized build agent and verify that the build is rejected.", + "Attributes": [ + { + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN01 Restrict Allowed Build Agents", + "SubSection": "", + "SubSectionObjective": "Ensure that builds are executed only on authorized build agents to maintain control over the build environment and prevent unauthorized code execution.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-3", "AC-6" ] } @@ -4176,80 +5144,25 @@ "Checks": [] }, { - "Id": "CCC.Core.CN08.AR01", - "Description": "When data is created or modified, the data MUST have a complete and recoverable duplicate that is stored in a physically separate data center.", + "Id": "CCC.Build.CN02.AR01", + "Description": "Attempt to trigger a build from an unauthorized external service or repository and verify that the build does not start.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", + "FamilyName": "Access Control", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN02 Restrict Allowed External Services for Build Triggers", "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", + "SubSectionObjective": "Ensure that builds can only be triggered by authorized external services or repositories to prevent unauthorized code execution or tampering.", "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement automated data replication processes to ensure that data is consistently duplicated in another region or availability zone. Regularly test data recovery from the replicated location to ensure integrity and availability. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "CP-2", - "CP-10" - ] - } - ] - } - ], - "Checks": [ - "cloudsql_instance_automated_backups", - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.Core.CN08.AR02", - "Description": "When data is replicated into a second location, the service MUST be able to accurately represent the replication locations, replication status, and data synchronization status.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN08 Replicate Data to Multiple Locations", - "SubSection": "", - "SubSectionObjective": "Ensure that data is replicated across multiple physical locations to protect against data loss due to hardware failures, natural disasters, or other catastrophic events.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH06" + "CCC.Core.TH01" ] } ], @@ -4257,22 +5170,14 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.PT-5" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "BCR-08", - "BCR-10", - "BCR-11" + "PR.AC-4" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "CP-2", - "CP-10" + "AC-3", + "AC-6" ] } ] @@ -4281,15 +5186,144 @@ "Checks": [] }, { - "Id": "CCC.Core.CN09.AR01", - "Description": "When the service is operational, its logs and any child resource logs MUST NOT be accessible from the resource they record access to.", + "Id": "CCC.Build.CN03.AR01", + "Description": "Attempt to access the build environment from an external network and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Build.CN03 Deny External Network Access for Build Environments", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Ensure that build environments do not have external network access to prevent unauthorized external access and data exfiltration.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH02", + "CCC.Core.TH05" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-5" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7", + "SC-5" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.CntrReg.CN01.AR01", + "Description": "Attempt to push an artifact with known vulnerabilities to the registry and observe if it is flagged or rejected by the vulnerability scanning process.", + "Attributes": [ + { + "FamilyName": "Risk Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN01 Implement Vulnerability Scanning for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that container images and artifacts stored in the container registry are scanned for vulnerabilities to identify and remediate security issues before deployment.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.CntrReg.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "RA-5", + "SI-5" + ] + } + ] + } + ], + "Checks": [ + "artifacts_container_analysis_enabled", + "gcr_container_scanning_enabled" + ] + }, + { + "Id": "CCC.CntrReg.CN02.AR01", + "Description": "Confirm that artifacts older than the specified retention period are automatically deleted from the registry.", + "Attributes": [ + { + "FamilyName": "Data Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.CntrReg.CN02 Implement Cleanup Policies for Artifacts", + "SubSection": "", + "SubSectionObjective": "Ensure that unused or outdated artifacts are cleaned up according to defined policies to manage storage effectively and reduce security risks associated with outdated versions.", + "Applicability": [ + "tlp-red", + "tlp-amber" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.Core.TH14" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-12" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN01.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials or generating temporary session tokens.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", + "SubSection": "", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", "Applicability": [ "tlp-clear", "tlp-green", @@ -4301,9 +5335,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH03" ] } ], @@ -4311,56 +5343,48 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" ] } ] } ], "Checks": [ - "logging_sink_created", - "cloudstorage_bucket_log_retention_policy_lock", - "iam_audit_logs_enabled" + "iam_sa_no_user_managed_keys", + "iam_no_service_roles_at_project_level" ] }, { - "Id": "CCC.Core.CN09.AR02", - "Description": "When the service is operational, disabling the logs for the service or its child resources MUST NOT be possible without also disabling the corresponding resource.", + "Id": "CCC.IAM.CN01.AR02", + "Description": "When a non-administrative principal attempts to create new credentials or a temporary session token, the service MUST deny the action.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN01 Restrict IAM User Credentials Creation", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", + "SubSectionObjective": "Prevent non-administrative principals from creating new long-lived credentials like access keys or generating temporary session tokens. This blocks a common privilege escalation and persistence vector.", "Applicability": [ "tlp-clear", "tlp-green", "tlp-amber", "tlp-red" ], - "Recommendation": "No normal business operations should disable logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging mechanisms are tightly integrated with service operations, so that logging cannot be disabled without stopping the service itself. ", + "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" + "CCC.IAM.TH03" ] } ], @@ -4368,21 +5392,589 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-6" + "PR.AA-05" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AU-9" + "AC-2", + "AC-3", + "AC-5", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_no_user_managed_keys", + "iam_no_service_roles_at_project_level" + ] + }, + { + "Id": "CCC.IAM.CN02.AR01", + "Description": "When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating, updating, or attaching policies.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", + "SubSection": "", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" ] }, { - "ReferenceId": "CCM", + "ReferenceId": "NIST_800_53", "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" + "AC-2", + "AC-3", + "AC-5", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_no_service_roles_at_project_level", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "CCC.IAM.CN02.AR02", + "Description": "When a non-administrative principal attempts to create, update, or attach policies, the service MUST deny the action.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN02 Restrict IAM Policies Modification", + "SubSection": "", + "SubSectionObjective": "Ensure that only designated administrative accounts have the ability to create, modify, or attach policies that define permissions for other identities.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-5", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_no_service_roles_at_project_level", + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "CCC.IAM.CN03.AR01", + "Description": "When a policy is created or updated that grants a principal permission to assume a role or impersonate a service identity, the principal MUST NOT contain a wildcard or be public/anonymous.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", + "SubSection": "", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_sa_enforce_separation_of_duties", + "iam_no_service_roles_at_project_level" + ] + }, + { + "Id": "CCC.IAM.CN03.AR02", + "Description": "When an external or unauthenticated principal tries to assume a role or impersonate a service identity, the service MUST deny the action.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN03 Restrict Role Assumption / Delegation", + "SubSection": "", + "SubSectionObjective": "Limit which principals can assume a role or impersonate a service identity to only those required. This prevents unintended cross-account or public access by securing the \"who can act as this identity\" boundary.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3", + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_role_sa_enforce_separation_of_duties", + "iam_no_service_roles_at_project_level" + ] + }, + { + "Id": "CCC.IAM.CN04.AR01", + "Description": "When an IAM policy is created or updated, it MUST NOT contain allow statements with wildcard permissions, unless the statement is restricted by a condition.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN04 Restrict Wildcard Usage in IAM Policies", + "SubSection": "", + "SubSectionObjective": "Limit the use of wildcard permissions in IAM policies to prevent overly broad access from being granted by default.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-6" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3", + "AC-6" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_no_administrative_privileges" + ] + }, + { + "Id": "CCC.IAM.CN05.AR01", + "Description": "When a new cloud account is provisioned, a password policy MUST be configured for IAM users following the minimum PCI DSS v4.0.1 configurations.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "Controls that restrict who can access and modify IAM resources.", + "Section": "CCC.IAM.CN05 Strong Password Policies for IAM Users", + "SubSection": "", + "SubSectionObjective": "Ensure that the password policies for IAM users have strong configurations.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a new cloud account is provisioned, a password policy must be configured for all IAM users to align with the minimum requirements defined in PCI DSS v4.0.1. This includes, at a minimum: strength: 0 # Not yet specified - reference-id: A password length of at least 12 characters. strength: 0 # Not yet specified - reference-id: A mix of upper- and lower-case letters, numbers, and special characters. strength: 0 # Not yet specified - reference-id: Prevention of the use of previously used passwords (password history). strength: 0 # Not yet specified - reference-id: Password expiration at a defined interval (e.g., every 90 days). strength: 0 # Not yet specified - reference-id: Account lockout after a defined number of failed login attempts.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-05" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-5" + ] + }, + { + "ReferenceId": "PCI-DSS", + "Identifiers": [ + "8.3.9", + "8.6.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.IAM.CN06.AR01", + "Description": "When a static credential such as an access key has existed for 90 days or more, it MUST be rotated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN06 Maximum Age for Long-Term Static Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that long-lived static credentials like access keys are programmatically rotated within a defined time period to limit the window of opportunity if compromised.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "When a static credential such as an access key has existed for 90 days or more, it must be automatically rotated to reduce the risk of compromise due to long-term exposure. Organizations should implement automated checks to identify aging credentials and enforce rotation policies. Additionally, access key usage should be regularly monitored, and credentials that are no longer in use should be deactivated or deleted promptly. Where possible, prefer temporary, short-lived credentials over long-lived static ones to further minimize risk.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH09", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_user_managed_key_rotate_90_days" + ] + }, + { + "Id": "CCC.IAM.CN07.AR01", + "Description": "When a user account is disabled or deleted in the organization's IdP, the corresponding cloud identity and its access policies MUST be disabled or deleted within 24 hours.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN07 Automate Identity De-provisioning", + "SubSection": "", + "SubSectionObjective": "Ensure that when an identity is terminated in the central Identity Provider (IdP), ts corresponding access to cloud resources is revoked automatically.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH10", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_service_account_unused", + "iam_sa_user_managed_key_unused" + ] + }, + { + "Id": "CCC.IAM.CN08.AR01", + "Description": "When an IAM user has credentials, such as passwords or access keys, that have not been used for 90 days or more, the unused credentials MUST be removed or deactivated.", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN08 Maximum Age for Unused Credentials", + "SubSection": "", + "SubSectionObjective": "Ensure that unused IAM credentals are removed to reduce exposure in the event of potential compromise.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "IAM user credentials (such as passwords or access keys) that have not been used for 90 days or more must be automatically removed or deactivated.", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH11", + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "iam_sa_user_managed_key_unused", + "iam_service_account_unused" + ] + }, + { + "Id": "CCC.IAM.CN09.AR01", + "Description": "When a human user accesses the cloud environment, they MUST authenticate through the organization's federated IdP via a standard protocol (e.g., SAML, OIDC).", + "Attributes": [ + { + "FamilyName": "Identity Provisioning and Lifecycle", + "FamilyDescription": "Controls related to the provisioning and lifecycle of IAM identities.", + "Section": "CCC.IAM.CN09 Enforce Federated Single Sign-On (SSO) for Human Users", + "SubSection": "", + "SubSectionObjective": "Ensure that all human users must authenticate through a central, federated Identity Provider (IdP) to access the cloud environment. This eliminates cloud-native user accounts with long-lived passwords, centralizes authentication controls, and simplifies lifecycle management.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01", + "CCC.IAM.TH09" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AA-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "IA-2" + ] + } + ] + } + ], + "Checks": [ + "compute_project_os_login_enabled" + ] + }, + { + "Id": "CCC.IAM.CN10.AR01", + "Description": "When suspicious API requests are detected, real time alerts MUST be generated to notify security personnel.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" + ] + } + ] + } + ], + "Checks": [ + "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", + "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled" + ] + }, + { + "Id": "CCC.IAM.CN10.AR02", + "Description": "When suspicious API requests are detected, the associated events MUST be logged, including the source details, time, and nature of the activity.", + "Attributes": [ + { + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN10 Alert On Anomalous Behaviour", + "SubSection": "", + "SubSectionObjective": "Ensure that logs and associated alerts are generated when anomalous API requests are made by a single identity, such as API requests commonly associated with privilege escalation tactics, originating from an external or malicious IP address or performed by a previously dormant identity, which may indicate that credentals may be compromised, as well as for password brute-force attempts and account lockouts.", + "Applicability": [ + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.IAM.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "DE.CM-03", + "DE.CM-06", + "DE.CM-09" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-4", + "SI-5", + "AC-2" ] } ] @@ -4390,78 +5982,21 @@ ], "Checks": [ "iam_audit_logs_enabled", - "logging_sink_created", - "cloudstorage_bucket_log_retention_policy_lock", - "compute_subnet_flow_logs_enabled", - "compute_loadbalancer_logging_enabled", - "compute_network_dns_logging_enabled" + "logging_sink_created" ] }, { - "Id": "CCC.Core.CN09.AR03", - "Description": "When the service is operational, any attempt to redirect logs for the service or its child resources MUST NOT be possible without halting operation of the corresponding resource and publishing corresponding events to monitored channels.", + "Id": "CCC.IAM.CN11.AR01", + "Description": "When a cloud account or organization is provisioned, the native automated access and usage analysis services MUST be enabled to continuously monitor for external or public access to resources, and unused access.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN09 Ensure Integrity of Access Logs", + "FamilyName": "Logging and Monitoring", + "FamilyDescription": "Controls that collect, alert, and retain IAM-related events.", + "Section": "CCC.IAM.CN11 Enable Continuous IAM Access and Usage Analysis", "SubSection": "", - "SubSectionObjective": "Ensure that access logs are always recorded to an external location that cannot be manipulated from the context of the service(s) it contains logs for.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "No normal business operations should result in the redirection of logs, as this could indicate an attempt to cover up unauthorized access. Ensure that logging configurations are immutable during service operation so that any changes require stopping the service and publishing corresponding events to monitored channels. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH07", - "CCC.TH09", - "CCC.TH04" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-6" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-9" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-02", - "LOG-04", - "LOG-09" - ] - } - ] - } - ], - "Checks": [ - "logging_sink_created", - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.Core.CN10.AR01", - "Description": "When data is replicated, the service MUST ensure that replication only occurs to destinations that are explicitly included within the defined trust perimeter.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN10 Restrict Data Replication to Trust Perimeter", - "SubSection": "", - "SubSectionObjective": "Ensure that data is only replicated on infrastructure in locations that are explicitly included within a defined trust perimeter.", + "SubSectionObjective": "Enable and configure the cloud provider's native access and usage analysis services to continuously monitor for external access paths and internal unused access.", "Applicability": [ + "tlp-clear", "tlp-green", "tlp-amber", "tlp-red" @@ -4471,7 +6006,978 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH04" + "CCC.IAM.TH02", + "CCC.IAM.TH10", + "CCC.IAM.TH11" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "ID.RA-01", + "ID.IM-01" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "CA-7", + "RA-5" + ] + } + ] + } + ], + "Checks": [ + "iam_account_access_approval_enabled", + "iam_cloud_asset_inventory_enabled" + ] + }, + { + "Id": "CCC.GenAI.CN01.AR01", + "Description": "Untrusted input such as user queries, RAG data or tool output MUST be validated before it is passed to a GenAI model.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN01.AR02", + "Description": "If malicious patterns such as prompt injection or sensitive data are detected during input validation, the input MUST be blocked or sanitised.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN01 Model Input Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate input before it is passed to a GenAI model in order to filter or sanitise adversarial queries and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Input Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0021", + "AML.M0015" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN02.AR01", + "Description": "GenAI model output MUST be validated for format conformance, malicious patterns, sensitive data and inapropriate content before being passed to users, application or plugins.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN02.AR02", + "Description": "In the event of policy violations, the AI-generated content MUST be redacted, encoded or rejected.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN02 Model Output Filtering and Sanitisation", + "SubSection": "", + "SubSectionObjective": "Inspect and validate GenAI model output before passing it to users, applications or plugins in order to filter or sanitise insecure or unreliable output and prevent sensitive data leakage.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH03", + "CCC.GenAI.TH04", + "CCC.GenAI.TH05", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-003", + "AIR-PREV-017", + "AIR-PREV-002", + "AIR-DET-001" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Output Validation and Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0020", + "AML.M0002" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN03.AR01", + "Description": "When data is designated for model training or RAG ingestion, then its source MUST be explicitly approved and its provenance documented.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN03.AR02", + "Description": "Data from unvetted sources MUST NOT be used in production systems.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN03 Data Provenance and Source Vetting", + "SubSection": "", + "SubSectionObjective": "Ensure that all data for training, fine-tuning or RAG comes from trusted, approved sources and is authorised for the intended purposes in order to prevent the initial introduction of malicious content or leaked sensitive data.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-006" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Management" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0025" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN04.AR01", + "Description": "When data is ingested for training, fine-tuning or conversion to vector embeddings, it MUST be validated for sensitive information or malicious content.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN04.AR02", + "Description": "If sensitive data or malicious content is detected, it must be rejected, redacted or flagged for manual review.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN04 Sanitisation of Ingested Data", + "SubSection": "", + "SubSectionObjective": "Validate and sanitise all data ingested by GenAI systems from extenal sources or internal knowledge bases, whether for training, conversion to vector embeddings, or real-time retireval, in order to remove or redact poisoned or sensitive data before further processing.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH02", + "CCC.GenAI.TH03" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-002" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Training Data Sanitization" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0007" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN05.AR01", + "Description": "When a RAG-enabled system generates a response containing information retrieved from its knowledge base, then the response MUST include a verifiable citation that links back to the specific source document.", + "Attributes": [ + { + "FamilyName": "Data", + "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters.", + "Section": "CCC.GenAI.CN05 Citations and Source Traceability", + "SubSection": "", + "SubSectionObjective": "Require the GenAI system to provide citations or direct links back to the source documents used to generate a response, in to enhance the transparency, trustworthiness, and verifiability of AI-generated content.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH09", + "CCC.GenAI.TH04" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-DET-013" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN06.AR01", + "Description": "When an LLM invokes an external tool (e.g., an API, a plugin), then the tool MUST operate with the least privileges required for performing its intended functionality.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration.", + "Section": "CCC.GenAI.CN06 Least Privilege for Plugins", + "SubSection": "", + "SubSectionObjective": "Restricts the permissions of any external tools the GenAI system can call to limit the potential damage if an agent is coerced to perform unintended actions or vulnerabilities in the tools are exploited.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH07", + "CCC.GenAI.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Agent Permissions" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN07.AR01", + "Description": "When an application makes an API call to a foundational model in a production environment, then it MUST specify an explicit version identifier.", + "Attributes": [ + { + "FamilyName": "Configuration Management", + "FamilyDescription": "The Configuration Management control family involves establishing, maintaining and monitoring the configuration of the service and related applications and infrastructure to ensure consistency, secure defaults and compliance.", + "Section": "CCC.GenAI.CN07 Model Version Pinning", + "SubSection": "", + "SubSectionObjective": "Mandate that applications are locked (\"pinned\") to a specific, tested version of a foundational model to prevent unexpected behaviour changes introduced by provider-side updates.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-010" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR01", + "Description": "When a new AI model is considered for production deployment, it MUST undergo a formal red teaming and quality assurance review.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.GenAI.CN08.AR02", + "Description": "If model quality review or red teaming identifies an issue that exceeds the organization's risk tolerance, the model MUST NOT be deployed until the issue is remediated.", + "Attributes": [ + { + "FamilyName": "Model Assurance and Evaluation", + "FamilyDescription": "The Model Assurance and Evaluation control family encompasses the proactiveand continuous processes of testing and validating the AI model's behavior to ensure it aligns with safety, ethical, and quality standards.", + "Section": "CCC.GenAI.CN08 Quality Control and Red Teaming", + "SubSection": "", + "SubSectionObjective": "Establish a formal program for quality evaluation and adversarial testing (red teaming) to ensure GenAI system meet all business, quality, security and compliance requirements before getting deployed into production environments.", + "Applicability": [ + "tlp-clear", + "tlp-green", + "tlp-amber", + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.GenAI.TH01", + "CCC.GenAI.TH02", + "CCC.GenAI.TH04", + "CCC.GenAI.TH08", + "CCC.GenAI.TH10" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "FINOS-AIGF", + "Identifiers": [ + "AIR-PREV-005" + ] + }, + { + "ReferenceId": "SAIF", + "Identifiers": [ + "Adversarial Training and Testing", + "Red Teaming", + "Product Governance" + ] + }, + { + "ReferenceId": "MITRE-ATLAS", + "Identifiers": [ + "AML.M0008" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN01.AR01", + "Description": "Verify that only authorized users can access MLDE resources, and that access modes are properly defined and enforced.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN01 Define Access Mode for ML Development Environments", + "SubSection": "", + "SubSectionObjective": "Ensure that access to Machine Learning Development Environment (MLDE) resources is strictly defined and controlled. Only authorized users with appropriate permissions can access these environments, mitigating the risk of unauthorized access, data leakage, or service disruption.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.1", + "2013 A.9.2.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-2", + "AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-01", + "IAM-02" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN03.AR01", + "Description": "Verify that root access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN03.AR02", + "Description": "For MLDE instances without sensitive data, ensure that root access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN03 Disable Root Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from obtaining root access on MLDE instances to reduce the risk of unauthorized system modifications and potential security breaches.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08", + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN04.AR01", + "Description": "Verify that terminal access is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN04.AR02", + "Description": "For MLDE instances without sensitive data, ensure that terminal access is only enabled when necessary and properly authorized.", + "Attributes": [ + { + "FamilyName": "Identity and Access Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN04 Disable Terminal Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent users from accessing the terminal on MLDE instances to limit the risk of unauthorized commands and potential system compromise.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-08" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.2.3" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN02.AR01", + "Description": "Confirm that file download functionality is disabled on MLDE instances containing sensitive data.", + "Attributes": [ + { + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.Core.TH02" ] } ], @@ -4485,14 +6991,21 @@ { "ReferenceId": "CCM", "Identifiers": [ - "DSP-10", - "DSP-19" + "DSI-05", + "DSI-07" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.2.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "AC-4" + "SC-7", + "SC-8" ] } ] @@ -4501,26 +7014,28 @@ "Checks": [] }, { - "Id": "CCC.Core.CN02.AR01", - "Description": "When data is stored, it MUST be encrypted using the latest industry-standard encryption methods.", + "Id": "CCC.MLDE.CN02.AR02", + "Description": "For MLDE instances without sensitive data, ensure that file downloads are monitored and logged.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN02 Encrypt Data for Storage", + "FamilyName": "Data Protection", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN02 Disable File Downloads on MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that all data stored is encrypted at rest using strong encryption algorithms.", + "SubSectionObjective": "Prevent unauthorized file downloads from MLDE instances to protect sensitive data from being exfiltrated.", "Applicability": [ + "tlp-red", + "tlp-amber", "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-clear" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.MLDE.TH02", + "CCC.Core.TH02" ] } ], @@ -4528,110 +7043,46 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.DS-5" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-03", - "CEK-04", - "UEM-08", - "DSP-17" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-13", - "SC-28" - ] - } - ] - } - ], - "Checks": [ - "compute_instance_encryption_with_csek_enabled", - "dataproc_encrypted_with_cmks_disabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption", - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled" - ] - }, - { - "Id": "CCC.Core.CN11.AR01", - "Description": "When encryption keys are used, the service MUST verify that all encryption keys use the latest industry-standard cryptographic algorithms.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "DSI-05", + "DSI-07" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.13.2.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "SC-7", + "SC-8" ] } ] } ], - "Checks": [ - "kms_key_rotation_enabled", - "dataproc_encrypted_with_cmks_disabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption", - "kms_key_not_publicly_accessible" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR02", - "Description": "When encryption keys are used, the service MUST rotate active keys within 180 days of issuance.", + "Id": "CCC.MLDE.CN05.AR01", + "Description": "Verify that only approved VM and container images can be selected when creating MLDE instances.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", "Applicability": [ + "tlp-red", "tlp-amber" ], "Recommendation": "", @@ -4639,7 +7090,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4647,53 +7098,43 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "kms_key_rotation_enabled", - "kms_key_not_publicly_accessible", - "dataproc_encrypted_with_cmks_disabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR03", - "Description": "When encrypting data, the service MUST verify that customer-managed encryption keys (CMEKs) are used.", + "Id": "CCC.MLDE.CN05.AR02", + "Description": "Attempt to create an MLDE instance with an unapproved image and confirm that it is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "", - "SubSection": "CCC.Core.CN11 Protect Encryption Keys", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "FamilyName": "Configuration Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN05 Restrict Environment Options on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual machine and container image options available when creating new MLDE instances to approved and secure configurations.", "Applicability": [ - "tlp-amber", "tlp-red" ], "Recommendation": "", @@ -4701,7 +7142,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.MLDE.TH04" ] } ], @@ -4709,51 +7150,371 @@ { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.DS-1" + "PR.IP-1" ] }, { "ReferenceId": "CCM", "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" + "TVM-02" ] }, { "ReferenceId": "ISO_27001", "Identifiers": [ - "2013 A.10.1.2" + "2013 A.12.5.1" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "SC-12", - "SC-17" + "CM-2" ] } ] } ], - "Checks": [ - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption", - "dataproc_encrypted_with_cmks_disabled", - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR04", - "Description": "When encryption keys are accessed, the service MUST verify that access to encryption keys is restricted to authorized personnel and services, following the principle of least privilege.", + "Id": "CCC.MLDE.CN06.AR01", + "Description": "Verify that automatic scheduled upgrades are enabled on user-managed MLDE instances containing sensitive data.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH04", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-12" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-01", + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.6.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN06.AR02", + "Description": "Ensure that the upgrade schedule is appropriately configured and does not interfere with critical operations.", + "Attributes": [ + { + "FamilyName": "Vulnerability Management", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN06 Require Automatic Scheduled Upgrades on User-Managed MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Ensure that MLDE instances are kept up-to-date with the latest security patches by enforcing automatic scheduled upgrades.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH04", + "CCC.Core.TH06" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.IP-12" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "TVM-01", + "TVM-02" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.12.6.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SI-2" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN07.AR01", + "Description": "Verify that MLDE instances containing sensitive data cannot be accessed via public IP addresses.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN07.AR02", + "Description": "For MLDE instances without sensitive data requiring public access, ensure that appropriate security controls are in place and access is approved.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN07 Restrict Public IP Access on MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Prevent public IP access to MLDE instances to reduce exposure to the internet and enhance security.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH02", + "CCC.VPC.TH02" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-3" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "SEF-05" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.13.1.1" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "SC-7" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN08.AR01", + "Description": "Verify that MLDE instances containing sensitive data can only be deployed in approved virtual networks with appropriate security controls.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.MLDE.CN08.AR02", + "Description": "Ensure that MLDE instances without sensitive data are deployed in networks that meet organizational security standards.", + "Attributes": [ + { + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.MLDE.CN08 Restrict Virtual Networks for MLDE Instances", + "SubSection": "", + "SubSectionObjective": "Limit the virtual networks that can be used when creating new MLDE instances to ensure they are deployed within approved and secure network environments.", + "Applicability": [ + "tlp-red", + "tlp-amber", + "tlp-green", + "tlp-clear" + ], + "Recommendation": "", + "SectionThreatMappings": [ + { + "ReferenceId": "CCC", + "Identifiers": [ + "CCC.MLDE.TH01", + "CCC.Core.TH01" + ] + } + ], + "SectionGuidelineMappings": [ + { + "ReferenceId": "NIST-CSF", + "Identifiers": [ + "PR.AC-4" + ] + }, + { + "ReferenceId": "CCM", + "Identifiers": [ + "IAM-12" + ] + }, + { + "ReferenceId": "ISO_27001", + "Identifiers": [ + "2013 A.9.1.2" + ] + }, + { + "ReferenceId": "NIST_800_53", + "Identifiers": [ + "AC-6" + ] + } + ] + } + ], + "Checks": [] + }, + { + "Id": "CCC.Message.CN01.AR01", + "Description": "Attempt to publish a message without using a customer-managed encryption key and verify that the message is rejected or not stored.", + "Attributes": [ + { + "FamilyName": "Encryption", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.Message.CN01 Use Customer-Managed Encryption Keys (CMEK) for Messages", + "SubSection": "", + "SubSectionObjective": "Ensure that messages are encrypted using customer-managed encryption keys (CMEK) to provide enhanced control over encryption processes and keys, meeting compliance and security requirements.", "Applicability": [ "tlp-clear", "tlp-green", @@ -4765,7 +7526,7 @@ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH16" + "CCC.Core.TH01" ] } ], @@ -4776,310 +7537,53 @@ "PR.DS-1" ] }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, { "ReferenceId": "NIST_800_53", "Identifiers": [ "SC-12", - "SC-17" + "SC-13" ] } ] } ], - "Checks": [ - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption", - "dataproc_encrypted_with_cmks_disabled" - ] + "Checks": [] }, { - "Id": "CCC.Core.CN11.AR05", - "Description": "When encryption keys are used, the service MUST rotate active keys within 365 days of issuance.", + "Id": "CCC.SvlsComp.CN01.AR01", + "Description": "Attempt to access the serverless function over the public internet and verify that access is denied.", "Attributes": [ { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", + "FamilyName": "Network Security", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN01 Enforce Use of Private Endpoints for Serverless Function", "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", + "SubSectionObjective": "Ensure that the serverless function is accessible only through a private endpoint, allowing it to communicate securely within a virtual private network and preventing unauthorized external access.", "Applicability": [ - "tlp-clear", - "tlp-green" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "kms_key_rotation_enabled", - "kms_key_not_publicly_accessible", - "dataproc_encrypted_with_cmks_disabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption" - ] - }, - { - "Id": "CCC.Core.CN11.AR06", - "Description": "When encryption keys are used, the service MUST rotate active keys within 90 days of issuance.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN11 Protect Encryption Keys", - "SubSection": "", - "SubSectionObjective": "Ensure that encryption keys are managed securely by enforcing the use of approved algorithms, regular key rotation, and customer-managed encryption keys (CMEKs).", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH16" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.DS-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "CEK-08", - "CEK-10", - "CEK-12" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.10.1.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "SC-12", - "SC-17" - ] - } - ] - } - ], - "Checks": [ - "kms_key_rotation_enabled", - "kms_key_not_publicly_accessible", - "dataproc_encrypted_with_cmks_disabled", - "bigquery_dataset_cmk_encryption", - "bigquery_table_cmk_encryption" - ] - }, - { - "Id": "CCC.Core.CN14.AR01", - "Description": "When backups are created for disaster recovery purposes, the storage mechanism MUST NOT allow modification or deletion within 30 days of creation.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Use immutable storage solutions where possible. Implement backup retention policies that enforce a minimum retention period of 30 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "cloudstorage_bucket_log_retention_policy_lock", - "cloudsql_instance_automated_backups" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 30 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-clear", - "tlp-green", + "tlp-red", "tlp-amber" ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 30 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "cloudsql_instance_automated_backups" - ] - }, - { - "Id": "CCC.Core.CN14.AR02", - "Description": "When backups are created for disaster recovery purposes, the most recent backup MUST have a creation date within the past 14 days.", - "Attributes": [ - { - "FamilyName": "Data", - "FamilyDescription": "The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle. These controls govern how data is transmitted, stored, replicated, and protected from unauthorized access, tampering, or exposure beyond defined trust perimeters. ", - "Section": "CCC.Core.CN14 Maintain Recent Backups", - "SubSection": "", - "SubSectionObjective": "Ensure that all backups used for disaster recovery are recent and subject to a retention policy that limits deletion.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "Implement automated backup processes to ensure that backups are created regularly. Monitor backup schedules and verify that the most recent backup creation date is within the last 14 days. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH06" - ] - } - ], - "SectionGuidelineMappings": [] - } - ], - "Checks": [ - "cloudsql_instance_automated_backups", - "cloudstorage_bucket_log_retention_policy_lock" - ] - }, - { - "Id": "CCC.Core.CN03.AR01", - "Description": "When an entity attempts to modify the service through a user interface, the authentication process MUST require multiple identifying factors for authentication.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH01" ] } ], "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" + "PR.AC-5" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "IA-2" + "SC-7", + "SC-8" ] } ] @@ -5088,990 +7592,45 @@ "Checks": [] }, { - "Id": "CCC.Core.CN03.AR02", - "Description": "When an entity attempts to modify the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", + "Id": "CCC.SvlsComp.CN02.AR01", + "Description": "Send requests to invoke the function up to the allowed threshold and confirm they are successful; then send additional requests exceeding the threshold from the same entity and verify that they are denied.", "Attributes": [ { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", + "FamilyName": "Availability", + "FamilyDescription": "TODO: Describe this control family", + "Section": "CCC.SvlsComp.CN02 Implement Function Invocation Rate Limits", "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", + "SubSectionObjective": "Ensure that function invocation is limited to a specified threshold from any single entity, preventing resource exhaustion and denial of service attacks.", "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" + "tlp-red", + "tlp-amber" ], "Recommendation": "", "SectionThreatMappings": [ { "ReferenceId": "CCC", "Identifiers": [ - "CCC.TH01" + "CCC.Core.TH12" ] } ], "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, { "ReferenceId": "NIST-CSF", "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" + "PR.DS-4" ] }, { "ReferenceId": "NIST_800_53", "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "apikeys_api_restrictions_configured", - "apikeys_key_exists", - "apikeys_key_rotated_in_90_days", - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "cloudsql_instance_public_ip", - "cloudstorage_bucket_public_access" - ] - }, - { - "Id": "CCC.Core.CN03.AR03", - "Description": "When an entity attempts to view information on the service through a user interface, the authentication process MUST require multiple identifying factors from the user.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" + "SC-5" ] } ] } ], "Checks": [] - }, - { - "Id": "CCC.Core.CN03.AR04", - "Description": "When an entity attempts to view information on the service through an API endpoint, the authentication process MUST require a credential such as an API key or token AND originate from within the trust perimeter.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN03 Implement Multi-factor Authentication (MFA) for Access", - "SubSection": "", - "SubSectionObjective": "Ensure that all sensitive activities require two or more identity factors during authentication to prevent unauthorized access.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-14" - ] - }, - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-7" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "IAM-03", - "IAM-08" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.9.4.2" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "IA-2" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "cloudsql_instance_public_ip", - "cloudsql_instance_public_access", - "cloudstorage_bucket_public_access", - "apikeys_api_restrictions_configured", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "compute_project_os_login_enabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR01", - "Description": "When an attempt is made to modify data on the service or a child resource, the service MUST block requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "cloudstorage_bucket_public_access", - "compute_instance_public_ip", - "cloudsql_instance_public_ip", - "compute_instance_ip_forwarding_is_enabled", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "gke_cluster_no_default_service_account", - "iam_no_service_roles_at_project_level", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused", - "iam_audit_logs_enabled", - "iam_account_access_approval_enabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR02", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_no_service_roles_at_project_level", - "iam_sa_no_administrative_privileges", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused", - "compute_project_os_login_enabled", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "compute_instance_public_ip", - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "cloudsql_instance_public_ip", - "cloudstorage_bucket_public_access", - "apikeys_api_restrictions_configured", - "apikeys_key_exists", - "apikeys_key_rotated_in_90_days", - "iam_cloud_asset_inventory_enabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR03", - "Description": "When administrative access or configuration change is attempted on the service or a child resource in a multi-tenant environment, the service MUST refuse requests across tenant boundaries unless the origin is explicitly included in a pre-approved allowlist.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "iam_no_service_roles_at_project_level", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused", - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "cloudsql_instance_public_ip", - "cloudsql_instance_public_access", - "cloudstorage_bucket_public_access", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "gke_cluster_no_default_service_account" - ] - }, - { - "Id": "CCC.Core.CN05.AR04", - "Description": "When data is requested from outside the trust perimeter, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "", - "SubSection": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "iam_no_service_roles_at_project_level", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused", - "gke_cluster_no_default_service_account", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "compute_instance_block_project_wide_ssh_keys_disabled", - "compute_instance_public_ip", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_firewall_rdp_access_from_the_internet_allowed", - "cloudsql_instance_public_ip", - "cloudsql_instance_public_access", - "cloudstorage_bucket_public_access", - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled", - "apikeys_api_restrictions_configured", - "apikeys_key_exists", - "apikeys_key_rotated_in_90_days" - ] - }, - { - "Id": "CCC.Core.CN05.AR05", - "Description": "When any request is made from outside the trust perimeter, the service MUST NOT provide any response that may indicate the service exists.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "cloudsql_instance_public_access", - "cloudstorage_bucket_public_access", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "gke_cluster_no_default_service_account", - "iam_no_service_roles_at_project_level", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused", - "apikeys_api_restrictions_configured", - "kms_key_not_publicly_accessible", - "compute_instance_ip_forwarding_is_enabled" - ] - }, - { - "Id": "CCC.Core.CN05.AR06", - "Description": "When any request is made to the service or a child resource, the service MUST refuse requests from unauthorized entities.", - "Attributes": [ - { - "FamilyName": "Identity and Access Management", - "FamilyDescription": "The Identity and Access Management control family ensures that only trusted and authenticated entities can access resources. These controls establish strong authentication, enforce multi-factor verification, and restrict access to approved sources to prevent unauthorized use or data exfiltration. ", - "Section": "CCC.Core.CN05 Prevent Access from Untrusted Entities", - "SubSection": "", - "SubSectionObjective": "Ensure that secure access controls enforce the principle of least privilege to restrict access to authorized entities from explicitly trusted sources only.", - "Applicability": [ - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "PR.AC-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "DSP-01", - "DSP-07", - "DSP-08", - "DSP-10", - "DSP-17" - ] - }, - { - "ReferenceId": "ISO_27001", - "Identifiers": [ - "2013 A.13.1.3" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AC-3" - ] - } - ] - } - ], - "Checks": [ - "compute_firewall_rdp_access_from_the_internet_allowed", - "compute_firewall_ssh_access_from_the_internet_allowed", - "compute_instance_public_ip", - "compute_instance_default_service_account_in_use", - "compute_instance_default_service_account_in_use_with_full_api_access", - "gke_cluster_no_default_service_account", - "cloudstorage_bucket_public_access", - "cloudsql_instance_public_access", - "cloudsql_instance_public_ip", - "cloudsql_instance_private_ip_assignment", - "apikeys_api_restrictions_configured", - "apikeys_key_exists", - "apikeys_key_rotated_in_90_days", - "kms_key_not_publicly_accessible", - "kms_key_rotation_enabled", - "iam_no_service_roles_at_project_level", - "iam_account_access_approval_enabled", - "iam_audit_logs_enabled", - "iam_role_kms_enforce_separation_of_duties", - "iam_role_sa_enforce_separation_of_duties", - "iam_sa_no_administrative_privileges", - "iam_sa_no_user_managed_keys", - "iam_sa_user_managed_key_rotate_90_days", - "iam_sa_user_managed_key_unused", - "iam_service_account_unused" - ] - }, - { - "Id": "CCC.Core.CN04.AR01", - "Description": "When administrative access or configuration change is attempted on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.Core.CN04.AR02", - "Description": "When any attempt is made to modify data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.Core.CN04.AR03", - "Description": "When any attempt is made to read data on the service or a child resource, the service MUST log the client identity, time, and result of the attempt.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN04 Log All Access and Changes", - "SubSection": "", - "SubSectionObjective": "Ensure that all access attempts are logged to maintain a detailed audit trail for security and compliance purposes.", - "Applicability": [ - "tlp-red" - ], - "Recommendation": "", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH01" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-3" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-08" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-2", - "AU-3", - "AU-12" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled" - ] - }, - { - "Id": "CCC.Core.CN07.AR01", - "Description": "When enumeration activities are detected, the service MUST publish an event to a monitored channel which includes the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement event publication mechanisms and alerts for patterns indicative of enumeration activities, such as repeated access attempts, requests, or liveness probes. Configure alerts to notify security teams of any activities that merit further investigation. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_sink_created" - ] - }, - { - "Id": "CCC.Core.CN07.AR02", - "Description": "When enumeration activities are detected, the service MUST log the client identity, time, and nature of the activity.", - "Attributes": [ - { - "FamilyName": "Logging & Monitoring", - "FamilyDescription": "The Logging & Monitoring control family ensures that access, changes, and security-relevant events are captured, monitored, and alerted on in order to provide visibility, support incident response, and meet compliance requirements. ", - "Section": "CCC.Core.CN07 Alert on Unusual Enumeration Activity", - "SubSection": "", - "SubSectionObjective": "Ensure that logs and associated alerts are generated when unusual enumeration activity is detected that may indicate reconnaissance activities.", - "Applicability": [ - "tlp-clear", - "tlp-green", - "tlp-amber", - "tlp-red" - ], - "Recommendation": "Implement logging mechanisms to capture details of enumeration activities, including client identity, timestamps, and activity nature. Retain logs according to organizational policies, and occasionally review them for patterns that may indicate reconnaissance activities. ", - "SectionThreatMappings": [ - { - "ReferenceId": "CCC", - "Identifiers": [ - "CCC.TH15" - ] - } - ], - "SectionGuidelineMappings": [ - { - "ReferenceId": "NIST-CSF", - "Identifiers": [ - "DE.AE-1" - ] - }, - { - "ReferenceId": "CCM", - "Identifiers": [ - "LOG-05", - "SEF-05" - ] - }, - { - "ReferenceId": "NIST_800_53", - "Identifiers": [ - "AU-6" - ] - } - ] - } - ], - "Checks": [ - "iam_audit_logs_enabled", - "logging_sink_created", - "logging_log_metric_filter_and_alert_for_audit_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_custom_role_changes_enabled", - "logging_log_metric_filter_and_alert_for_bucket_permission_changes_enabled", - "logging_log_metric_filter_and_alert_for_project_ownership_changes_enabled", - "logging_log_metric_filter_and_alert_for_sql_instance_configuration_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_network_route_changes_enabled", - "logging_log_metric_filter_and_alert_for_vpc_firewall_rule_changes_enabled" - ] } ] } diff --git a/prowler/lib/outputs/compliance/ccc/ccc.py b/prowler/lib/outputs/compliance/ccc/ccc.py new file mode 100644 index 0000000000..99a6c91cd9 --- /dev/null +++ b/prowler/lib/outputs/compliance/ccc/ccc.py @@ -0,0 +1,98 @@ +from colorama import Fore, Style +from tabulate import tabulate + +from prowler.config.config import orange_color + + +def get_ccc_table( + findings: list, + bulk_checks_metadata: dict, + compliance_framework: str, + output_filename: str, + output_directory: str, + compliance_overview: bool, +): + section_table = { + "Provider": [], + "Section": [], + "Status": [], + "Muted": [], + } + pass_count = [] + fail_count = [] + muted_count = [] + sections = {} + for index, finding in enumerate(findings): + check = bulk_checks_metadata[finding.check_metadata.CheckID] + check_compliances = check.Compliance + for compliance in check_compliances: + if compliance.Framework == "CCC": + for requirement in compliance.Requirements: + for attribute in requirement.Attributes: + section = attribute.Section + + if section not in sections: + sections[section] = {"FAIL": 0, "PASS": 0, "Muted": 0} + + if finding.muted: + if index not in muted_count: + muted_count.append(index) + sections[section]["Muted"] += 1 + else: + if finding.status == "FAIL" and index not in fail_count: + fail_count.append(index) + sections[section]["FAIL"] += 1 + elif finding.status == "PASS" and index not in pass_count: + pass_count.append(index) + sections[section]["PASS"] += 1 + + sections = dict(sorted(sections.items())) + for section in sections: + section_table["Provider"].append(compliance.Provider) + section_table["Section"].append(section) + if sections[section]["FAIL"] > 0: + section_table["Status"].append( + f"{Fore.RED}FAIL({sections[section]['FAIL']}){Style.RESET_ALL}" + ) + else: + if sections[section]["PASS"] > 0: + section_table["Status"].append( + f"{Fore.GREEN}PASS({sections[section]['PASS']}){Style.RESET_ALL}" + ) + else: + section_table["Status"].append(f"{Fore.GREEN}PASS{Style.RESET_ALL}") + section_table["Muted"].append( + f"{orange_color}{sections[section]['Muted']}{Style.RESET_ALL}" + ) + + if ( + len(fail_count) + len(pass_count) + len(muted_count) > 1 + ): # If there are no resources, don't print the compliance table + print( + f"\nCompliance Status of {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Framework:" + ) + total_findings_count = len(fail_count) + len(pass_count) + len(muted_count) + overview_table = [ + [ + f"{Fore.RED}{round(len(fail_count) / total_findings_count * 100, 2)}% ({len(fail_count)}) FAIL{Style.RESET_ALL}", + f"{Fore.GREEN}{round(len(pass_count) / total_findings_count * 100, 2)}% ({len(pass_count)}) PASS{Style.RESET_ALL}", + f"{orange_color}{round(len(muted_count) / total_findings_count * 100, 2)}% ({len(muted_count)}) MUTED{Style.RESET_ALL}", + ] + ] + print(tabulate(overview_table, tablefmt="rounded_grid")) + if not compliance_overview: + if len(fail_count) > 0 and len(section_table["Section"]) > 0: + print( + f"\nFramework {Fore.YELLOW}{compliance_framework.upper()}{Style.RESET_ALL} Results:" + ) + print( + tabulate( + section_table, + tablefmt="rounded_grid", + headers="keys", + ) + ) + print(f"\nDetailed results of {compliance_framework.upper()} are in:") + print( + f" - CSV: {output_directory}/compliance/{output_filename}_{compliance_framework}.csv\n" + ) diff --git a/prowler/lib/outputs/compliance/compliance.py b/prowler/lib/outputs/compliance/compliance.py index bb7fbf1146..d399900837 100644 --- a/prowler/lib/outputs/compliance/compliance.py +++ b/prowler/lib/outputs/compliance/compliance.py @@ -3,6 +3,7 @@ import sys from prowler.lib.check.models import Check_Report from prowler.lib.logger import logger from prowler.lib.outputs.compliance.c5.c5 import get_c5_table +from prowler.lib.outputs.compliance.ccc.ccc import get_ccc_table from prowler.lib.outputs.compliance.cis.cis import get_cis_table from prowler.lib.outputs.compliance.csa.csa import get_csa_table from prowler.lib.outputs.compliance.ens.ens import get_ens_table @@ -104,6 +105,15 @@ def display_compliance_table( output_directory, compliance_overview, ) + elif compliance_framework.startswith("ccc_"): + get_ccc_table( + findings, + bulk_checks_metadata, + compliance_framework, + output_filename, + output_directory, + compliance_overview, + ) else: get_generic_compliance_table( findings, diff --git a/tests/lib/outputs/compliance/ccc/__init__.py b/tests/lib/outputs/compliance/ccc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/lib/outputs/compliance/ccc/ccc_aws_test.py b/tests/lib/outputs/compliance/ccc/ccc_aws_test.py new file mode 100644 index 0000000000..39460fd0ec --- /dev/null +++ b/tests/lib/outputs/compliance/ccc/ccc_aws_test.py @@ -0,0 +1,138 @@ +from io import StringIO +from unittest import mock + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.ccc.ccc_aws import CCC_AWS +from prowler.lib.outputs.compliance.ccc.models import CCC_AWSModel +from tests.lib.outputs.compliance.fixtures import CCC_AWS_FIXTURE +from tests.lib.outputs.fixtures.fixtures import generate_finding_output +from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1 + + +class TestAWSCCC: + def test_output_transform_evaluated_requirement(self): + findings = [ + generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}) + ] + + output = CCC_AWS(findings, CCC_AWS_FIXTURE) + output_data = output.data[0] + + assert isinstance(output_data, CCC_AWSModel) + assert output_data.Provider == "aws" + assert output_data.AccountId == AWS_ACCOUNT_NUMBER + assert output_data.Region == AWS_REGION_EU_WEST_1 + assert output_data.Description == CCC_AWS_FIXTURE.Description + assert output_data.Requirements_Id == CCC_AWS_FIXTURE.Requirements[0].Id + assert ( + output_data.Requirements_Description + == CCC_AWS_FIXTURE.Requirements[0].Description + ) + attribute = CCC_AWS_FIXTURE.Requirements[0].Attributes[0] + assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName + assert ( + output_data.Requirements_Attributes_FamilyDescription + == attribute.FamilyDescription + ) + assert output_data.Requirements_Attributes_Section == attribute.Section + assert output_data.Requirements_Attributes_SubSection == attribute.SubSection + assert ( + output_data.Requirements_Attributes_SubSectionObjective + == attribute.SubSectionObjective + ) + assert ( + output_data.Requirements_Attributes_Applicability == attribute.Applicability + ) + assert ( + output_data.Requirements_Attributes_Recommendation + == attribute.Recommendation + ) + assert ( + output_data.Requirements_Attributes_SectionThreatMappings + == attribute.SectionThreatMappings + ) + assert ( + output_data.Requirements_Attributes_SectionGuidelineMappings + == attribute.SectionGuidelineMappings + ) + assert output_data.Status == "PASS" + assert output_data.StatusExtended == "" + assert output_data.ResourceId == "" + assert output_data.ResourceName == "" + assert output_data.CheckId == "service_test_check_id" + assert output_data.Muted is False + + def test_output_transform_manual_requirement(self): + # Use a finding for the evaluated requirement so the manual one is appended + # by the manual-loop branch (Checks=[]). + findings = [ + generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}) + ] + + output = CCC_AWS(findings, CCC_AWS_FIXTURE) + # data[0] is the evaluated PASS row, data[1] is the manual row + manual_row = output.data[1] + + assert isinstance(manual_row, CCC_AWSModel) + assert manual_row.Provider == "aws" + assert manual_row.AccountId == "" + assert manual_row.Region == "" + assert manual_row.Description == CCC_AWS_FIXTURE.Description + assert manual_row.Requirements_Id == CCC_AWS_FIXTURE.Requirements[1].Id + manual_attribute = CCC_AWS_FIXTURE.Requirements[1].Attributes[0] + assert ( + manual_row.Requirements_Attributes_FamilyName == manual_attribute.FamilyName + ) + assert manual_row.Requirements_Attributes_Section == manual_attribute.Section + assert manual_row.Status == "MANUAL" + assert manual_row.StatusExtended == "Manual check" + assert manual_row.ResourceId == "manual_check" + assert manual_row.ResourceName == "Manual check" + assert manual_row.CheckId == "manual" + assert manual_row.Muted is False + + @freeze_time("2025-01-01 00:00:00") + @mock.patch( + "prowler.lib.outputs.compliance.ccc.ccc_aws.timestamp", + "2025-01-01 00:00:00", + ) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output(compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}) + ] + output = CCC_AWS(findings, CCC_AWS_FIXTURE) + output._file_descriptor = mock_file + + with patch.object(mock_file, "close", return_value=None): + output.batch_write_data_to_file() + + mock_file.seek(0) + content = mock_file.read() + + # Header check: AWS-specific columns must be present + header = content.split("\r\n", 1)[0] + assert "ACCOUNTID" in header + assert "REGION" in header + assert "REQUIREMENTS_ATTRIBUTES_FAMILYNAME" in header + assert "REQUIREMENTS_ATTRIBUTES_SECTION" in header + assert "REQUIREMENTS_ATTRIBUTES_APPLICABILITY" in header + assert "REQUIREMENTS_ATTRIBUTES_SECTIONTHREATMAPPINGS" in header + # Header should NOT contain Azure or GCP-only columns + assert "SUBSCRIPTIONID" not in header + assert "PROJECTID" not in header + + # Body checks: evaluated row + manual row + rows = [r for r in content.split("\r\n") if r] + assert len(rows) == 3 # header + evaluated + manual + assert "CCC.Core.CN01.AR01" in rows[1] + assert "PASS" in rows[1] + assert AWS_ACCOUNT_NUMBER in rows[1] + assert AWS_REGION_EU_WEST_1 in rows[1] + assert "CCC.IAM.CN01.AR01" in rows[2] + assert "MANUAL" in rows[2] + assert "manual_check" in rows[2] + # The frozen timestamp should appear + assert "2025-01-01 00:00:00" in rows[1] diff --git a/tests/lib/outputs/compliance/ccc/ccc_azure_test.py b/tests/lib/outputs/compliance/ccc/ccc_azure_test.py new file mode 100644 index 0000000000..a3a2f7d028 --- /dev/null +++ b/tests/lib/outputs/compliance/ccc/ccc_azure_test.py @@ -0,0 +1,99 @@ +from io import StringIO +from unittest import mock + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.ccc.ccc_azure import CCC_Azure +from prowler.lib.outputs.compliance.ccc.models import CCC_AzureModel +from tests.lib.outputs.compliance.fixtures import CCC_AZURE_FIXTURE +from tests.lib.outputs.fixtures.fixtures import generate_finding_output +from tests.providers.azure.azure_fixtures import AZURE_SUBSCRIPTION_ID + +AZURE_LOCATION = "westeurope" + + +class TestAzureCCC: + def test_output_transform_evaluated_requirement(self): + findings = [ + generate_finding_output( + provider="azure", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=AZURE_SUBSCRIPTION_ID, + region=AZURE_LOCATION, + ) + ] + + output = CCC_Azure(findings, CCC_AZURE_FIXTURE) + output_data = output.data[0] + + assert isinstance(output_data, CCC_AzureModel) + assert output_data.Provider == "azure" + assert output_data.SubscriptionId == AZURE_SUBSCRIPTION_ID + assert output_data.Location == AZURE_LOCATION + assert output_data.Description == CCC_AZURE_FIXTURE.Description + assert output_data.Requirements_Id == CCC_AZURE_FIXTURE.Requirements[0].Id + attribute = CCC_AZURE_FIXTURE.Requirements[0].Attributes[0] + assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName + assert output_data.Requirements_Attributes_Section == attribute.Section + assert ( + output_data.Requirements_Attributes_Applicability == attribute.Applicability + ) + assert output_data.Status == "PASS" + assert output_data.CheckId == "service_test_check_id" + + def test_output_transform_manual_requirement(self): + findings = [ + generate_finding_output( + provider="azure", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=AZURE_SUBSCRIPTION_ID, + region=AZURE_LOCATION, + ) + ] + output = CCC_Azure(findings, CCC_AZURE_FIXTURE) + manual_row = output.data[1] + + assert isinstance(manual_row, CCC_AzureModel) + assert manual_row.Provider == "azure" + assert manual_row.SubscriptionId == "" + assert manual_row.Location == "" + assert manual_row.Requirements_Id == CCC_AZURE_FIXTURE.Requirements[1].Id + assert manual_row.Status == "MANUAL" + assert manual_row.CheckId == "manual" + + @freeze_time("2025-01-01 00:00:00") + @mock.patch( + "prowler.lib.outputs.compliance.ccc.ccc_azure.timestamp", + "2025-01-01 00:00:00", + ) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output( + provider="azure", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=AZURE_SUBSCRIPTION_ID, + region=AZURE_LOCATION, + ) + ] + output = CCC_Azure(findings, CCC_AZURE_FIXTURE) + output._file_descriptor = mock_file + + with patch.object(mock_file, "close", return_value=None): + output.batch_write_data_to_file() + + mock_file.seek(0) + content = mock_file.read() + header = content.split("\r\n", 1)[0] + assert "SUBSCRIPTIONID" in header + assert "LOCATION" in header + assert "ACCOUNTID" not in header + assert "PROJECTID" not in header + assert "REGION" not in header + rows = [r for r in content.split("\r\n") if r] + assert len(rows) == 3 + assert "CCC.Core.CN01.AR01" in rows[1] + assert AZURE_SUBSCRIPTION_ID in rows[1] + assert "CCC.IAM.CN01.AR01" in rows[2] + assert "MANUAL" in rows[2] diff --git a/tests/lib/outputs/compliance/ccc/ccc_gcp_test.py b/tests/lib/outputs/compliance/ccc/ccc_gcp_test.py new file mode 100644 index 0000000000..9ba2127235 --- /dev/null +++ b/tests/lib/outputs/compliance/ccc/ccc_gcp_test.py @@ -0,0 +1,99 @@ +from io import StringIO +from unittest import mock + +from freezegun import freeze_time +from mock import patch + +from prowler.lib.outputs.compliance.ccc.ccc_gcp import CCC_GCP +from prowler.lib.outputs.compliance.ccc.models import CCC_GCPModel +from tests.lib.outputs.compliance.fixtures import CCC_GCP_FIXTURE +from tests.lib.outputs.fixtures.fixtures import generate_finding_output + +GCP_PROJECT_ID = "test-project" +GCP_LOCATION = "europe-west1" + + +class TestGCPCCC: + def test_output_transform_evaluated_requirement(self): + findings = [ + generate_finding_output( + provider="gcp", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=GCP_PROJECT_ID, + region=GCP_LOCATION, + ) + ] + + output = CCC_GCP(findings, CCC_GCP_FIXTURE) + output_data = output.data[0] + + assert isinstance(output_data, CCC_GCPModel) + assert output_data.Provider == "gcp" + assert output_data.ProjectId == GCP_PROJECT_ID + assert output_data.Location == GCP_LOCATION + assert output_data.Description == CCC_GCP_FIXTURE.Description + assert output_data.Requirements_Id == CCC_GCP_FIXTURE.Requirements[0].Id + attribute = CCC_GCP_FIXTURE.Requirements[0].Attributes[0] + assert output_data.Requirements_Attributes_FamilyName == attribute.FamilyName + assert output_data.Requirements_Attributes_Section == attribute.Section + assert ( + output_data.Requirements_Attributes_Applicability == attribute.Applicability + ) + assert output_data.Status == "PASS" + assert output_data.CheckId == "service_test_check_id" + + def test_output_transform_manual_requirement(self): + findings = [ + generate_finding_output( + provider="gcp", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=GCP_PROJECT_ID, + region=GCP_LOCATION, + ) + ] + output = CCC_GCP(findings, CCC_GCP_FIXTURE) + manual_row = output.data[1] + + assert isinstance(manual_row, CCC_GCPModel) + assert manual_row.Provider == "gcp" + assert manual_row.ProjectId == "" + assert manual_row.Location == "" + assert manual_row.Requirements_Id == CCC_GCP_FIXTURE.Requirements[1].Id + assert manual_row.Status == "MANUAL" + assert manual_row.CheckId == "manual" + + @freeze_time("2025-01-01 00:00:00") + @mock.patch( + "prowler.lib.outputs.compliance.ccc.ccc_gcp.timestamp", + "2025-01-01 00:00:00", + ) + def test_batch_write_data_to_file(self): + mock_file = StringIO() + findings = [ + generate_finding_output( + provider="gcp", + compliance={"CCC-v2025.10": "CCC.Core.CN01.AR01"}, + account_uid=GCP_PROJECT_ID, + region=GCP_LOCATION, + ) + ] + output = CCC_GCP(findings, CCC_GCP_FIXTURE) + output._file_descriptor = mock_file + + with patch.object(mock_file, "close", return_value=None): + output.batch_write_data_to_file() + + mock_file.seek(0) + content = mock_file.read() + header = content.split("\r\n", 1)[0] + assert "PROJECTID" in header + assert "LOCATION" in header + assert "ACCOUNTID" not in header + assert "SUBSCRIPTIONID" not in header + assert "REGION" not in header + rows = [r for r in content.split("\r\n") if r] + assert len(rows) == 3 + assert "CCC.Core.CN01.AR01" in rows[1] + assert GCP_PROJECT_ID in rows[1] + assert "CCC.IAM.CN01.AR01" in rows[2] + assert "MANUAL" in rows[2] diff --git a/tests/lib/outputs/compliance/fixtures.py b/tests/lib/outputs/compliance/fixtures.py index 7b29411663..41c68d148f 100644 --- a/tests/lib/outputs/compliance/fixtures.py +++ b/tests/lib/outputs/compliance/fixtures.py @@ -1,5 +1,6 @@ from prowler.lib.check.compliance_models import ( AWS_Well_Architected_Requirement_Attribute, + CCC_Requirement_Attribute, CIS_Requirement_Attribute, Compliance, Compliance_Requirement, @@ -1022,3 +1023,169 @@ PROWLER_THREATSCORE_M365 = Compliance( ), ], ) + + +# CCC fixtures cover the three providers Prowler ships catalogs for. Each +# fixture has one auto-evaluated requirement (with Checks) and one manual +# requirement (Checks=[]) so test suites can exercise both paths. +CCC_AWS_FIXTURE = Compliance( + Framework="CCC", + Name="Common Cloud Controls Catalog (CCC)", + Provider="AWS", + Version="v2025.10", + Description="Common Cloud Controls Catalog (CCC) for AWS", + Requirements=[ + Compliance_Requirement( + Checks=["service_test_check_id"], + Id="CCC.Core.CN01.AR01", + Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Data", + FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + Section="CCC.Core.CN01 Encrypt Data for Transmission", + SubSection="", + SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + Applicability=["tlp-green", "tlp-amber", "tlp-red"], + Recommendation="Most cloud services enable TLS 1.3 by default.", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]} + ], + ) + ], + ), + Compliance_Requirement( + Checks=[], + Id="CCC.IAM.CN01.AR01", + Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials or generating temporary session tokens.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Identity and Access Management", + FamilyDescription="Controls that restrict who can access and modify IAM resources.", + Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation", + SubSection="", + SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.", + Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"], + Recommendation="", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]} + ], + ) + ], + ), + ], +) + +CCC_AZURE_FIXTURE = Compliance( + Framework="CCC", + Name="Common Cloud Controls Catalog (CCC)", + Provider="Azure", + Version="v2025.10", + Description="Common Cloud Controls Catalog (CCC) for Azure", + Requirements=[ + Compliance_Requirement( + Checks=["service_test_check_id"], + Id="CCC.Core.CN01.AR01", + Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Data", + FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + Section="CCC.Core.CN01 Encrypt Data for Transmission", + SubSection="", + SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + Applicability=["tlp-green", "tlp-amber", "tlp-red"], + Recommendation="Most cloud services enable TLS 1.3 by default.", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]} + ], + ) + ], + ), + Compliance_Requirement( + Checks=[], + Id="CCC.IAM.CN01.AR01", + Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Identity and Access Management", + FamilyDescription="Controls that restrict who can access and modify IAM resources.", + Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation", + SubSection="", + SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.", + Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"], + Recommendation="", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]} + ], + ) + ], + ), + ], +) + +CCC_GCP_FIXTURE = Compliance( + Framework="CCC", + Name="Common Cloud Controls Catalog (CCC)", + Provider="GCP", + Version="v2025.10", + Description="Common Cloud Controls Catalog (CCC) for GCP", + Requirements=[ + Compliance_Requirement( + Checks=["service_test_check_id"], + Id="CCC.Core.CN01.AR01", + Description="When a port is exposed for non-SSH network traffic, all traffic MUST include a TLS handshake AND be encrypted using TLS 1.3 or higher.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Data", + FamilyDescription="The Data control family ensures the confidentiality, integrity, availability, and sovereignty of data across its lifecycle.", + Section="CCC.Core.CN01 Encrypt Data for Transmission", + SubSection="", + SubSectionObjective="Ensure that all communications are encrypted in transit to protect data integrity and confidentiality.", + Applicability=["tlp-green", "tlp-amber", "tlp-red"], + Recommendation="Most cloud services enable TLS 1.3 by default.", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.Core.TH02"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "CCM", "Identifiers": ["CEK-03", "CEK-04"]} + ], + ) + ], + ), + Compliance_Requirement( + Checks=[], + Id="CCC.IAM.CN01.AR01", + Description="When an identity policy for a non-administrative principal is evaluated, it MUST NOT grant permissions for creating credentials.", + Attributes=[ + CCC_Requirement_Attribute( + FamilyName="Identity and Access Management", + FamilyDescription="Controls that restrict who can access and modify IAM resources.", + Section="CCC.IAM.CN01 Restrict IAM User Credentials Creation", + SubSection="", + SubSectionObjective="Prevent non-administrative principals from creating new long-lived credentials.", + Applicability=["tlp-clear", "tlp-green", "tlp-amber", "tlp-red"], + Recommendation="", + SectionThreatMappings=[ + {"ReferenceId": "CCC", "Identifiers": ["CCC.IAM.TH03"]} + ], + SectionGuidelineMappings=[ + {"ReferenceId": "NIST-CSF", "Identifiers": ["PR.AA-05"]} + ], + ) + ], + ), + ], +) From 7eb204fff0eb5ea123ce239b10b9c3e092fd5490 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:39:43 +0200 Subject: [PATCH 29/36] docs: classify supported providers by category on main page (#10621) Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- docs/introduction.mdx | 70 ++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 766f60e3c0..5747eeadb1 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -21,29 +21,57 @@ ## Supported Providers -The supported providers right now are: +Prowler supports a wide range of providers organized by category: -| Provider | Support | Audit Scope/Entities | Interface | -| -------------------------------------------------------------------------------- | ---------- | ---------------------------- | ------------ | -| [AWS](/user-guide/providers/aws/getting-started-aws) | Official | Accounts | UI, API, CLI | -| [Azure](/user-guide/providers/azure/getting-started-azure) | Official | Subscriptions | UI, API, CLI | -| [Google Cloud](/user-guide/providers/gcp/getting-started-gcp) | Official | Projects | UI, API, CLI | -| [Kubernetes](/user-guide/providers/kubernetes/getting-started-k8s) | Official | Clusters | UI, API, CLI | -| [M365](/user-guide/providers/microsoft365/getting-started-m365) | Official | Tenants | UI, API, CLI | -| [Github](/user-guide/providers/github/getting-started-github) | Official | Organizations / Repositories | UI, API, CLI | -| [Oracle Cloud](/user-guide/providers/oci/getting-started-oci) | Official | Tenancies / Compartments | UI, API, CLI | -| [Alibaba Cloud](/user-guide/providers/alibabacloud/getting-started-alibabacloud) | Official | Accounts | UI, API, CLI | -| [Cloudflare](/user-guide/providers/cloudflare/getting-started-cloudflare) | Official | Accounts | UI, API, CLI | -| [Infra as Code](/user-guide/providers/iac/getting-started-iac) | Official | Repositories | UI, API, CLI | -| [MongoDB Atlas](/user-guide/providers/mongodbatlas/getting-started-mongodbatlas) | Official | Organizations | UI, API, CLI | -| [OpenStack](/user-guide/providers/openstack/getting-started-openstack) | Official | Projects | UI, API, CLI | -| [Vercel](/user-guide/providers/vercel/getting-started-vercel) | Official | Teams / Projects | CLI | -| [LLM](/user-guide/providers/llm/getting-started-llm) | Official | Models | CLI | -| [Image](/user-guide/providers/image/getting-started-image) | Official | Container Images | CLI, API | -| [Google Workspace](/user-guide/providers/googleworkspace/getting-started-googleworkspace) | Official | Domains | CLI | -| **NHN** | Unofficial | Tenants | CLI | +### Cloud Service Providers (Infrastructure) -For more information about the checks and compliance of each provider visit [Prowler Hub](https://hub.prowler.com). +| Provider | Support | Audit Scope/Entities | Interface | +| -------------------------------------------------------------------------------- | ---------- | ------------------------ | ------------ | +| [Alibaba Cloud](/user-guide/providers/alibabacloud/getting-started-alibabacloud) | Official | Accounts | UI, API, CLI | +| [AWS](/user-guide/providers/aws/getting-started-aws) | Official | Accounts | UI, API, CLI | +| [Azure](/user-guide/providers/azure/getting-started-azure) | Official | Subscriptions | UI, API, CLI | +| [Cloudflare](/user-guide/providers/cloudflare/getting-started-cloudflare) | Official | Accounts | UI, API, CLI | +| [Google Cloud](/user-guide/providers/gcp/getting-started-gcp) | Official | Projects | UI, API, CLI | +| **NHN** | Unofficial | Tenants | CLI | +| [OpenStack](/user-guide/providers/openstack/getting-started-openstack) | Official | Projects | UI, API, CLI | +| [Oracle Cloud](/user-guide/providers/oci/getting-started-oci) | Official | Tenancies / Compartments | UI, API, CLI | + +### Infrastructure as Code Providers + +| Provider | Support | Audit Scope/Entities | Interface | +| --------------------------------------------------------------------- | -------- | -------------------- | ------------ | +| [Infra as Code](/user-guide/providers/iac/getting-started-iac) | Official | Repositories | UI, API, CLI | + +### Software as a Service (SaaS) Providers + +| Provider | Support | Audit Scope/Entities | Interface | +| ----------------------------------------------------------------------------------------- | -------- | ---------------------------- | ------------ | +| [GitHub](/user-guide/providers/github/getting-started-github) | Official | Organizations / Repositories | UI, API, CLI | +| [Google Workspace](/user-guide/providers/googleworkspace/getting-started-googleworkspace) | Official | Domains | CLI | +| [LLM](/user-guide/providers/llm/getting-started-llm) | Official | Models | CLI | +| [M365](/user-guide/providers/microsoft365/getting-started-m365) | Official | Tenants | UI, API, CLI | +| [MongoDB Atlas](/user-guide/providers/mongodbatlas/getting-started-mongodbatlas) | Official | Organizations | UI, API, CLI | +| [Vercel](/user-guide/providers/vercel/getting-started-vercel) | Official | Teams / Projects | CLI | + +### Kubernetes + +| Provider | Support | Audit Scope/Entities | Interface | +| -------------------------------------------------------------------------- | -------- | -------------------- | ------------ | +| [Kubernetes](/user-guide/providers/kubernetes/getting-started-k8s) | Official | Clusters | UI, API, CLI | + +### Containers + +| Provider | Support | Audit Scope/Entities | Interface | +| ------------------------------------------------------------------- | -------- | -------------------- | --------- | +| [Image](/user-guide/providers/image/getting-started-image) | Official | Container Images / Registries | CLI, API | + +### Custom Providers (Prowler Cloud Enterprise Only) + +| Provider | Support | Audit Scope/Entities | Interface | +| -------------------- | -------- | -------------------- | --------- | +| VMware/Broadcom VCF | Official | Infrastructure | CLI | + +For more information about the checks and compliance of each provider, visit [Prowler Hub](https://hub.prowler.com). ## Where to go next? From ca50b24d7708d06132721fd11491dbdbf806e54e Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:40:44 +0200 Subject: [PATCH 30/36] docs: add Vercel Cloud getting started (#10609) --- .../providers/select-vercel-prowler-cloud.png | Bin 0 -> 151052 bytes docs/images/providers/vercel-launch-scan.png | Bin 0 -> 82946 bytes docs/images/providers/vercel-team-id-form.png | Bin 0 -> 79526 bytes docs/images/providers/vercel-token-form.png | Bin 0 -> 91853 bytes .../vercel/getting-started-vercel.mdx | 56 +++++++++++++++++- 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 docs/images/providers/select-vercel-prowler-cloud.png create mode 100644 docs/images/providers/vercel-launch-scan.png create mode 100644 docs/images/providers/vercel-team-id-form.png create mode 100644 docs/images/providers/vercel-token-form.png diff --git a/docs/images/providers/select-vercel-prowler-cloud.png b/docs/images/providers/select-vercel-prowler-cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..b332103e1ff1187a4d6796436f20d45c09abe698 GIT binary patch literal 151052 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%0AMH!$VOFG;00c4uLy#;7gyHofMpXR}2w-lfi z%pH4_Ui3Y@B&^0`=r-2w6xr0?W}xmx%>wi=p`Y@iVG7J}eLq_YDW0|*@O$!DLJbl( zWi0sKm|CUlz|F|;H!8q{+i#)H%1T#;iIrtzx|oZJX&m8_=J|1QPA;hMiS73t7PZ{K z_p=SzdXM4cy4;4DnObrgmeWuilsEvp4@3h3;=Pfy7Kt3O@KUOYMoBEcp2j0*HV7U-wAk7vO!=WtMS{iMpg z)HTyB&Ifs5>gmtO~tA9xzB3sm)S1j!8`xVC6JzA6{?oRCz%*x_mOz+W;tR74g)g+^gC)F zEj1=JqLPy>s}IUX+bze#B&x8voa8tH+SthH`9@kdMz@DkhiKy#kMd}xEG z)K15AmfOi**~bL#N%rXqbaspYq_GG5mi-QrFFyxId;?_FvA5|ki099daYyXmoUID` zsD`GrMU0lCGExr>4>57}t74`9EivxffC0L-jLqH=6Vs26k8jV(!`=bSn8?=F@w9rh z1#;=1cWAzdwP6FO9*d-|u&QeXE}IV;@AjI*{W2KGkB;gz1^nX&Q$k1}PTbs_hNO&? z40}Y&e=q2v90^(&H|gA7d(kpZORxHd9eZ~mS(?09rN(50A@w$Q32f%ITEW~t^1f({ z;P`3)cDuQx2F5f+u4M@Mtzc2<{qtS>@kqW}cb%^`-2&t`)sB17jv(5yc-GT=v=S}V z>yt(5UNA`lVCNv+V7n~qp)s4=)%ffHm?ucAZ(vQyx98=!T5t4(mkn-v0X`H;4Ys^M zGLuoN-7xYtzy=6M3kRtQRs1i2gLPE7Z~tka+BdwT)&rw9R8 ziNf2u)v$=0b^r@=o9Hv7#463((nUYQFcIeFI<(k*R~q5pl$8j-J@79Q=s%9aK7AO= zqF3O#7WSN&u5@0D{*=n5rrZ~HzzGXD5DI}&Px`>FrM8+aAOAh^zV{o$Z=FcZ8nZ8E zkFXY#`Qe|xj0rqzv@h8c!S{t^u$b51S}5%wHQcBL1=(uRUdIllvkry

vPR@eJx4 z&v&{^!QqjGo|RjTK7I^1m4^1mgF@IaX(;=5`KJn93Mjs z_Bib7?G+aiLfUh+=URz-@jG)>rq_FefDnsGDOFS!S;2Si)HTF{8#D?MRxQ=g9EdL= zJ(w+<$o`!4EH9Cs!cQ&o4{YQy0!$H`)AJ*qOG3rLoxn78^pq?V@#S&0fkJZnYeR@G zfP0d@Tf5+gv3oThaCfB3*WKNiJE4r#d3rvnPD*{XKftCT$Hg7~SV3!xiBv&bq^Xp?Jh88J@_vev>+|Ix4 z)8YS-$KwmFmsofiZWfUhX+Si@2D=SAN-(V@0`I$KN9w%wkyt6_xJHJ{yvD zvttSk>*>i#GxsEy+tQ@H&hxm{>-qGMJLqjJsg(^FO| z?KZLDTA}yl$98jtNg^4%6d3R~P0feXOWcw`52SKvBuoQ5u)eZLrKU>^kb!ekm_8GE$!(! zt(&;0_nv692hF!xc?2%fs3OG}bxVE8JB3vAx5I!XpQ=0+1D`Jje{jR0#%R?Y6fyFv z&Q{Ga9hGUbS$1FWZ>@=^M`!&yNdT;GFOoSpxkkj{F)$ur8UB`mb=F~=%4PPx8-r5i z30Ot}YBPO^(CC2`F7N#KmdpKaScH07w}kb}v`|1fEr)Kk{v2oogiAXkDJ#pnr_b&9 ze#FyFH^(n6O@{6?8tFTW_=_BK2=`3uT+AR^|R! z^n7xvu~;(04D{n=IkQ>leZ2|451nd#eBTLp&ryz#o0~p1p46S+LQTs4h|bH6ThXsk z)BWigLC8sq?43ag$OCEv?eFv$IW&^ltSHwAW^%E1%6iOeg9k_karecb28U0} z^OF;!{EUMj*VC-pu5utNWbdN?tt(x~pLzWuemb00SjV3dbzvi!_h7|xWB6fu2>VHB z3D|cA+%ns2I|Gqx`b=CMF3Kb~t>jVKA?W`p?@Tk)Yg zBq5S$v7xZQEw_mz{Tk3p#ba@a-%c3Ip%AdLe`5=Y$uETG7ujB?l)@h*zU?|u=Y^HKOTAw_8FwS*Bg`^#Pjnm$4;23NJ%bap5Vo-|KV7-M&kYfpWu6T?C>{m~ z;bEtiMB@CLaQ9UPOhQ6(pz}JmaZZB;(i5)TH$%4;{k7@zD=c00f{YJ^hVXE*lj+Sd z(RxJ+Wt}5MmUEi6$_IIElAfcbyn@{K1&MbeCBYHJ2ZpL8(ofp>MZ3ghs!NluSvDHe z_zoSmTD$y*)ovGX7t2#c9-)B4<%l(#Mha8B7aE&Dr_)AHoz|;a`GxwU4?sE_U&iI~ z7D-OYt|bJ!WS1u*V-p8-^m>|%~U#z*e(zDuf%*IOld^7Lyjn)yS2mfh`f1ykzAg6{(#Y_+))yD! z>Tx%^ykIt1Rk%BOXTWXN_@L zmaWC*1x=}9i4JjglaQ8a78KoK4OT96bLli}xc4@0>=yWXDG= z4}zhE{`AIphlYmR+~WE(sFaxSq!Q6j0Bn8t`5^^A!iu9$N^#DSeII@Zqh47Z>oiC_ z{&V&3C<|gN&`(Ez$DgWNY;c=&7jGz0qsMJM^piOh87`++umAQ`+iUDY#~5yHtx>44 z&SM)K-u9(+-(%T3Xv5niel(eL{%oErxG9otw3>?^#@z+VucO#3hT`=~`dY-$y(&!t zV$Zj|SM?E7bZgGu$xu=L-qCnfzY&xx%TvZT9w6&Cj|(lYR1Z+=}wN$uUDB{~+1O#yUnF z#kV;<*)qFQpb`+_<^Uk%jRj1vd#D-F)r`2l{yKA0Vr%JtKyLslxeFJFK)&?*BmoNt z8gxggQq_BXiPV(Mr{OSdD6%Ra-q6yO_ zq|3_bpE^t{{V}~|+Pv-RrLpl&K0{`l#>>7ko|o`si}bDBcIX-__kDp4K{VXy0BTDi zuUF%?((UVND77xNI?WR|@F$g|%Vh-H+`kO~0kuT#jPrevT={YdVkO2u(@LAl(CMn> zRvNJtAy%h`fqn6X-xNGOA6YMZwC&)a(SIWcylpy`mJJZ7=+Kt6xpt>7FSVl8CJ4Sn z-^DO)fBubd+gBPS02Zot7K9u?)sbxnH|g0B@-&XVRkg{4l~T8?QhZAy3g_y2yWpsM zy*uCg7Fje(ap|?;&F=WGiGq`~y#>?jpZdJR7^f^Q5hev;Hn$lN5QGBS5O3Yf#N<0r zvC=*=mKz*1yy1qVud%SfVYo7{md4DsUg0G@9Fr?O?PJU(ex)AU_~F}S`2texl~8CQ z4Td1_q^%O7cVj@wb+v$6tnRGCNy=aynf?!7-yIHT*R7A}qD4dyHA+MfJvtFYPe}BV z=)HHw5J94ZAbN|a(R()$qPGx69isO(7;X6Nyyu+X_kHK}o_}0(xs>PG&wkck>t6SL zF9zQtvC3h;_FOrou&Cpcvm|K3mVL?6IL(<)F zv*Z+LQzEO<#A-wvp0Ig_ewZM{aW*QKidSG_>bn_#2MTYcO3s>3mBcW*GDCyq= zyv9(wip9N&p5)GQiD-LA!^#IvoA73d4v@;)zK^6Gu2|amWzSf>@hhQN|2wP5i4v~Y zvu9=H7J+lNDAv*!9DQE!4Y|_LP{&hiuIp1p-nJaK?`+nQdI)mq&#WIuT(jF{0@b-G zqFBm(L-1i}S$O&Po=FmX{4%vQdD+x&xw)^uSlqaMd+||JP_C-J;tIFKkJ(G5GdJRc zYv+dv4^9ki#=aK%A6`r4AsU0)PN`vurI>ay_q&^&$ad{y8X=Fqu_=Hct-=PYbaHg` zEbi<&?L6kv&$WE-zjyOVrA0BF?2{*V9$p-RKC5eL8>Y<-ar7oUo1nV7IBOLaQ;dH)pGFeHYJ^;LH$4nckX4e8D>(+l)>}Kxw~{G=eT5>y$oKLz0i*=8 z2{bq9@J|Z;SuU)ncuSP_vp=e2tK&v~j8A`CEkg*_BNP%Q8-FnYgGLGbI-EC%lf?P`HRRi&QKRW=@vCu? zKtFj#1#F+2Z*x}sB+po#8rJZ$zp6KsUVMnv9BFDBF|2}=Q85OuG#Lie3cB9W3x3Ts zV61#3z8oTAq43sG=Pvq`l-w&pA-}W9_58RkfzPBph|jBQW?93)AoV==v2X2mttHu5 z+K&6h_1}>F?DBQ%SwldJci`SZG#i4}IXl$*+;P%)l5V#VP_j!G2U_ng8Brq1ci%8v zZlL(q1KEdl2j&#hboujcGeO38pUbm^u3n$|lmR`}11_HCV+qT!bmkPHlGusL++5vJ8(lJ%GNMS(aT&@gv)PKam^Ag`HpBSIbJ!Y zP;}aAUA}Jjwllj9O5f|4AN>*2Yx|x1avzwOnxL0kD?R3AdbizU1GZ0p#SXYnjj8h4 zPkPN9*PEnOy}Ed?hWHY7!d>Gqa}T(Fqe{U$A}_+Ztc$6j*%*muLxMn6Y07U}yIx+~y?J{hw0Ovyax?AB)7=r! z>cac4nN1o;;gb-Mk4MTWWE?&+wlj#k_q<1(36u8^#zQF(FYH0Y;%Q%snw;qmzY4fz z6)_kM8e?l{mauSIxGxWpL;TRA&)Hgk6l>ch8yX1Y-5YAW+lH)H zW8@(?(D4iKNoZS`iDi6$-N!dj2Y>h7CfRRQ1@4Pu>yVnLu&?jw+h0)C?%ljPrbJ7# z0qM9U)+%nZO5g=9+N8dyh`h@dOQIr&X}Gh~Hl$Wl-eXKFKC)Qw%bj3-u(1m-{e%X> z46i26eIu5^z=Ejsc^fJ(Ck+a>zp2NUWt=cSYV>p}5e$-45MOOh5!L@FjbOvT6qkb_ z(CF$_=PciisA&V7yXZzjX{>HZ78%t6|3R{6O@LZXZ zgI5O932E21H!tygMFN~y+OK|%|3W{zF0uDjaUtL&%+~l3Ml#Q-RpNFB3D|lu7}$Fl zT+!ZZ8ejLa2fNFs4~Yl8pjq${5#rFHhQNbfu!`NU!0w0idjbKT% zpD+dC(K7j;za?0U$N5RmjDAhIMam$Vx~=EopZ}sf21t!SCGyA-M~Kk>64D}@4yLN$T0r>y0jR9#?+TpKzdE(`%yWf>sTd|>iuOO9dt?)$w^R-h{!d-=^o?#Bn z#l9qdjmMR(0Ndn|4Y?lA;D7$pT*%kK&$*=I-6OZB%a<387Ra-wKTYIvG&?_t4mO(g zCGy66J$fKQ-kZRaAZV+l?Dsu#Cp`TP`;7w*O#J2U`-$u;yA*`}>moaOH9}pfd5U&xuwEEptl>^sL8-4z*T5FQVL|~59D*~Aj zv5J0MP~AI_CdTi^aQpVXt*PpSuP@tv#jv~tp1=2cUv#M{DOIMfP31+Ee>t(A6zFW0 z-Dyx(%aG(kQayOM@>r0zyj| zB)ij41|J=O?eZ-3B*dWV)p1NPQpXNG^w>EXH}pcyO{mbM6`V3bX?c1Qy#FM^I}Z0k;r@~8NC zF8%e%`^m%~c6Xg7s;n!^mz^C_;F7ZU)FYz={dX~2{7=)^x>(U4D)|Ymm~^0*(&W{u zN<-xpjhCCLoM+5`YhwKWx4q5>OHvzZJAfc~P4k9+XdzV0$qN?UrdLLcZ^(*Xl~v# zbGJmieof(Zk_xj>L+waO-+z(Mxbfmy=r>Z@v?AP78E|M!l;6C6let*0`X*FLYNk(z zl^_|1K3ARKl>yzSV&5zR_5O3w{C z%E7q}BgbKugAN3wvsUYP!YRTKvLW>K|X0MMEra(IEP9#s=RTYg|-SoN!eTlQ_J4;;spzoan0JNdf;OxU=;E7V@?@w8kmjwe52kpJqsO3UPlw;x zaGj;OOp3-!b?4tzm~#bQDESsfqMPHw=HB7=r`FC#pZ4YjpZUJ7M=q}Z9ODWZ1YEw6 z_s!2cOYF!PIq6ey%M#1Q*EI!PX^oCR$P_}~dF1qLettgNqgYQqvs3KtA;cFY(os%Q zRuJ$gAEo0w-~QfB68$P552wLx+b-EaL*3Kv>9wAW9#9zqusO4aWkuTv0t0pcFD z?HA>q8*rY2OIS-hvj|{V(5R8yyFm;(iv{GN_)4f~J5|SK9;L;y! z*gT?BC)s?#3rQecEi0~P{?XXNs>@&d`nTrA{&|tsaYVhIi6pk$aTmNmb839bZnmY( zCV88V_7=WaDRXdmHZorUM#bHpm{q9^_t%k)6Uu&@eGl zuWSj464c#)6l!~O#WBt?W#jL+|KHyUEW8_?$G=+6^6o(ETQ42;cziH1-!#+1&iqkg ztnXl&NyCaBf{Mq;?!hbE>$e&8YaIl$+(jriXoVf@2y2bX)9U#ME6}{^H{A^@+zM`m za51Kh4&Y2|Dn!u>5`W3cQepE!In0<1rb}pOhnKLiusjld|Kc;) z9lR3xD!io7Hi5fC)M~Z`VqvtKk|E|~{TQ^;UmC#X;(60WF=Dlf^^!mX z#CA&G9dUFWV#oN02wrw{NGtR-^OoG!L}lpO>~`eN?bNGVkN>^(oq}$3A+ef&07>n4 zjUpXhr1Q|XK=~^9F%hG#?U2m0w0UvdFzugyz_oF>1mate$Ls@6zKF}y4#1ELzNJ{r z*H#FqO*5TI;bUiD)_KMsaNq zpq~ry&q5q7`jRTM9cLw7QY5!9BcTrtZsa{U4Q1_N;5kJUY;U0;l;+n z*`CO%XX1O$0X{wflQOk`b6zo^q&H11NK-Wbl@M>I#scBBP>PlhiUWLLq^7L?|yA#OX*B~%a|FV zA}f-!S@?B>T^JidW;pw!_lI+{F7Wrdcbc3Wvp!siXefR4Oh!@O`Nd(A!mG&O$6-(X zHgO8OiII{(k4G)+VVABu*f)Xf@3@|rAq7>du|quAxkO1VAKS3$*1J%iEH`GD?WUnw z^)hO@qW;6iB6qe>+tGTop}6U2FoDlt;e9Im?)UIgtKyHq*y30B8ZOaT|AbcYWY@eL z(Qw+}dgy>*LpKn$yL}O6YbypFqcL{Bfv(@Z!3}$2ols8D;^`iWXaBoMY+oucbME_B z`_!IGqThrrkr+09r^ly-9o|2fmU`xJO71j>^axWQjGekfxpjb+CoTr;K;$!=~8pVk8sKa_KVX+L81ew zw_g>Y$xY=*&z8<&fMo28Y$h!JWZ&p&%Ci$&bY6J7sQRsp-xK~4?cUn1zeR4;k>eW- z>5*u%smI~!(S8fV^t>LkT8E}u=-JJllqWl2zquz*I&&n_t<=X(K>m; z_~Fd$Ro_h>ihf9!%jHF<@nVfpt=OdB@lVS)Cl~u0EcM#LG-Q9QCU#mFIALmuHp|A+ zo_s%fBuyQ({@b9tqTk7%&k}330g_>xQapL}Xj@pRC3X;;0KY?Uh0cKWRI=GS~%eGaP2V z=JQ^^?rP_*Q(?x@<~bQrzkh+3VMP~yI>w4g8ZN9Rd3Z3J4c~(FxoabBf>x!QQ3W z(RA=W;*7z1CXy4UV5XR#B|Ez5bWk{M(BR}GfxyMK@#w?e7M`H(Sd6;lna1)(%ebFo zB#kg{!d}{Zi&|PkqNg7WD3n~M2^*REa9|l!2fn+bqIU)Yy)Ohjnk36#J_gQ+$`01i zfUMX#GLs6UK{f+su!jHnnl`nl-IIpbyJy>z#i8QJP2_%QEyCR(D2<}UG{P3W>_mR} zINfhuH%Y*};Y30Y=H40k4=@=fJJyL>rf0I06wrd2T?yiCZf$JR^~x^G8=F z0H0choA16}!y}Fd?1I8NL%pF}n7kGGsB}HcIdyW%SP(sJ1{TWGgN%xFQ8sF>N{A!dV9IdrI$PiEEzuC)iV=8oOBazH5N_k$zc1R zmxluL-%EA+vtFwLP{ya1IJG7qA^8|eU#H%JUgoUyuac=-2(r~N-I0Wt z_h}nxhxC@{oy(tAHk z7P99ChOakvAsbtstjzP7)1HG)T&v>xKNdVAo<*K*ZhW)Uacy-W{B3g%M;s@NO(xz8 z!aGdZnyTprmf)`^ee_nM8$*(I7}V*`S7vHoj?-H&n>$pYTSLBO1tW8yFr)ni(%Bv) z6w15x)j#i#uh0G0FPBQAq`tay38V1@a)FB*PiRswKn#oDDjzo?*ob`>WvBo26|S&M=K*`%DCL2KtnE>jQuVO znoc?jKiIxPo=O>itey2Sl#giY+?#E`8zss8`Sa)fcSnau`i@--P>7PvXvsod)IS`$ zb1DH?&HUv4Y=J2O7=)ZsXSFM;7Q2a#{tub=Krw2sg)o#uIl@l#NWMn?;^lI>{<=EN zqCPJ-x92->gK}Ld$u+E8=2{#t|I)$M`JqVZ)5E=y&12)vNWt_YeoK{D{ycSM;0qmb z8}Wj_gIx86(}nvqkNmq1OZ*|gRd0VC5^xUs zm;W#8jQ0`Z|7D%=^uMh$pr0QH_l^JMoMB2Qy?c4Qfa>@9xXi!X=Ikl~fDW$X`6{>RTvP7q=PHtXHBW810XC zbX&kctR~XFJzPG8cu^ef>DO8pnwA2ut6Q|b2@EZl@;AI2x6uKa$2gC)_MFx-Xh-3 z8pC5%)1X%~lY(z%O(WL@`+hZ`Ryi2_ca8rTtxOChi&@6sf_tFd0wG*iBfWLr1ZD@s zb>6y8ODxf**!y}Pbsm7=f7j(;m3*y`ehT<&3q9r?@LV0AXkzqXj&_GA;V58ZZvz`t z<(AWZsQjwYLuk5)<7H6Ms?F$E+TNQR;-~jCb0YxkUi!u|wL8^eI{STh3kYtF-4_nS z*-2B(MP#PD#+-~tdSj0sQBk<&)L8=454Ko@4ecL?>FSSiVCJ?`>a-ThO9ntDLRy-)rym=Kerphj&!3ML-mLfyNVkU^R5z<1s)LHD-}cNn(~Y zeiuJ(i+Jy6s|=~)oArhUzvTB{O?VMq!^}J%@U~zpO!zeeLlKEJTMOkqJ$uTN!z#6# zwvbI8sNj*9m&W|rP7Ckj=FzCb5A%g!C1va?qHFu!pe|aAjHVM< zrd&rU={en2*O(KlonQU{80`M86P;K9eRTb#KQNV!pY>##3G z=i9)Ndhj2TeNTV}{{fd-oUT#SdF^FIj9dry7Bl(O-@xpI0sv}1RoRg^E zt1MdPsNOYIjH-BIJOMlX7#OSYCn&FaX?e|?0()D!6pSwV%M6QwMnbcyDD(+lp!)f& zu~#?#p-wFXQb%g%u|4k45HL=cbtJC!b~P4j8w&&orJYhznE$)W^f7|;OaC*~Kkn!` znt9y&mzy(qUN2vc?e2Y|zoCau_qY^mxNx|T@IK=`6F9Zo9e4RoZv_Q9_g_Cx*Fd;6@(Jtm+fX+#EWj|5%x6Ys$9MwO-MIkR{MJ_R=4*nC{ynd3LVmlpirAU> zmn}5Np+#;ig^w>i`2%!(mt2Tezc+u{9o5V>-t@hCV|t=eMHNXuod29cx8x96DZup! zu+p~gc-Kl~SjaW1E2Si;$8Wo!zml?7v9<6!7poneo)b|E&Iz8KqjE#)ai>Cby%!w%bRFRizRcA3RZQ8`>YTW6Op&hVHvun)KK~ z*fZR6UyI?jE>gRgECSxpomRLlY8M;l#mmb{Q;CP4BM_GAsw+4{4g21L=tkW}i^$d4 z0wMI&NVoY^m3;#Ivz-D4CN`P$zkLb3@!%N?^#Mn&%A0uWAr}GxY_cJd7sz)?M&{Y- zD*Y#<7h;oRkr`%eJw;$LgdcK?C6+wZDyWDDcHCt9)>T!PHtifas%_*_>}ouexmh`Q zJ~38JNs{^8ZZpC>4C?5mDz%M8=qZeMe;aziNfn{b!T)(f%<-~! zyM**%2yx?#0rJIJnGD0z2N!GXVit#x?Ru&u;Co#K)%WSUK>s|d8&uu$pgUVE80nXd za4%7Gl8AgADgtZ4*#qhE#HJ(hS22`e?S?^vS$Ueu5#o%#D)t&waNAWsb_RXtv?iz_ z^2{fzV9(!ZtVq|KL8xwL!CJR+$XI}4^I~aYW$C??qZ}p%YL7I-|4M3Bu|ssZ2oPrWz#(0vy-;IwPn3aZoM~a9QI{%gRk zdx}6)B|uWT#&PPtet&xxczplOeG zIi5_w?MK=qzoaw68c^dxHyxp>30qDB(@ZHSR0xo#?BwOnr3X_`DU zvVV!F)h-E87aKv9BvY$+AOYE|)+P%km4>zsaNX8;(y+rvGDZ9y50OJMXHM(=VjDlyYu3mJ-skb3Hy)Tp zj!(>Kx@_5-2x{s9>Czvn(z978QhdI>uPmeq@t(sDAF)^EhI3Ss_?BxI6F;xNt}43! z8w-0?`ItePBw>d>bMQ5l*4_VzVt)m-U}ounmS?w>U$Em44^in7pCVTlww?qePvj@P z|FimYF4zLLCtogGpkOxh_5U3R|N0X~T+g0RANcfBe{xkJpyPjU{LaeWG`W;$5v|m* zWbpe(4E?Dvh4lNBUYW()|9M+~y}W@~MA0(FufE@a%gFGrhCj3^X`Ob{oM-F4h^rH8 z!!eGRe)8l;ujs%ODGjenwx5JUYAtE(9@F1%1zgNG%A5DTV>BBD`*yg09+dONNqR(i zmWm$Miw9HsEc{z$+u9_o(W0I`WQ$c8`ZvJK|KViW3WuC)-^5hAhVo^{l`xRI7jgsmJe(USr69h?XFte`Fr5; zK0>@KAqX^K9;(!4ARy(jFJ-&`HQrC)l!AkS{JE93HvfGky&4;cE?PB1MB6_Vrn5Y7 zrpTs}%mxO5WW{l(@s9PbKa2|c;~{yu(_f1m5AXlin*8fi3yX9BB4PWM>7i~Q`CWz6 z&GFLZZ&1|gf(BE?8@lfx5V^DkAZ}36>RZX$j8;@n`yuB*ld=_W`y+T0yJeU8B_)l( z$b^&L?eJ^l|NFfML0%~x1M@V-bFkh7I~%a=_fgtL2|Jd3@#PtQO!kvCt_4*#qw)xE z)U_m0``q)b9PMnslYI~UBtG-S-qH@`DEj8jmAX>4rwQEf#t*({X{a3S9m)NRP=?;c z0)CK5FgV#0UB4d3ez6+|Ji1g{PA#$yHiW-bbAbsy^w4?5lwir%!=8L*s}CEu7I-s~ zowecyVaM{@w|O-V&W)k`-R`Nb#Iq17Wq^nH4j&|2c<37~xQVXLG?t1V9vE*Xx;Lpc zE{!n(EM#FZWlwYQw}L;9|AqIZ<^I9iBkId7`0!VE{i%LgnD@95Ot0zi$k)SAZK2tH z_u0upth!iU0`vj~?Y#^0?K?Ewkppr`gW0s;G5g6Lu^q_0cOM5f-BmYwWEJuj?5XU$Jm3CkcZ)S`V_(^v!lC;k&qcyvfE)5+8#qL3vBm{SOoo zzcvDkwY)fOva+MU>m*4KIY3D&%;-EH3l;NfU)xO;Uc z4j!IzP)KC9Y2Lt5qvW0Ed0e0yFPekMv%EZg<9E2U;sWpb{nsF%k&#PF6agV&yu*xd z*pb-$hlq_Hw}-}mJI28CXp#@WXogP{;%cPgq%zhB8<-YPR_CM=oPVG@D^C@1)dM|U zW>hjGYJ%VLNoA>ai2+miE$--8wnwFyo0IPAPl1o-=8)i!xc9Kv`$!2^iVo;qOw2&g zJA4T@?@yP|1YOtrwpyhz#2fIGSFZ8_EslUCbOf7?i)B~q$~6}1DPpkba);sOoE>bj z?=+!v?})hQ9Bs{TMn(8M1xG#C`}YJw(hM17JfPcJ;=20gOmJ0ax$i>e4=xO5wAG$1 z398L-2nxQup`uH}r5X#&C89P)@?d^PYnNtcNA@mr(hE);aI|-k_GCS8bz=yan$Wlq&sLRVDB~ zA|eiK^zIJg4OR{gj*&Gn&w4d~y{e(5Y#?gPTM!&p7OR40Drk?Xo~DfIhssbR{OFJHFw zulYpk1}*B<bGbsNdp`0QUJm}DE7yvU(Tw#{*b>|A*)i-T&Yn}_ zpi@!r;&|F&d)*XCf%>I*CYQFzYlbORFP?##dDF9*=ZgFZ19OLpQF;fBdPmOuEFTLr zi#|TpoSJF2PID(7XOM7d$M)uIbgXcnJ521gw^TWy>;k<7gOvE( zpEXhzFmzL@v0e!vObXW2G|`tXSpwvB(8ENJxV==jd2*}}{;GNG6%?)#wyq*s7+Y#{ z1R0Azq^S~*7;}cl@FfgadHB}vFByau=~X`tA!c|zOE~0=099ATWD%!TuWb_$a>jS$ zA|PIC!!F0WOulr*eeGqUA;1XJObo53i3O&#r=g2(; zh92J?D9hTKb?)1Kk(1s_G>4{0YHvMZn%hhE6!e%l{w|6%8lap#W5(=~=oQ-19%YM| z$vukPffa6k$fg7e$gK5ku~XwxBzxm4EF4W?nk{F znznVM!iNj&ph6*?_N*-^m6FNIvgwA;stLKzX__Z^C+-c;ruP=6h}VL>D)H#z+&e`O z=DI>MmEaG1wLaiDc@W;&QZ0XxcS(D9=VArs0Rt9B(MGVmvCp#X^``AlPn@^y)Khdr zuSma~C~?l;1j!DU&Y$qC{d)dfFsCx9UBlLd$2h&28_DV(AC-3ZF6Vf_XIzej1%9@V zZc-|h(Xz6#Dh1(Bv<)3lTfx-^1sZa`7f3cM?Rpp10^4=7QoZU)>}QbWv85DdW@e2W z3*pA-O^~{T36FmEba?8`ue&LN^!((0Lo4l9O;z`@2T0}5s17tip6<$K?!LqGKzv#f zzpFtt=qTAR!#!f4+`JDan>JU&sLG&WMNOZ#W>zSZ+u=7>{%DG5U-$NcyA*6}Ps+Y$ zckyWUT7NrSnA+-JkNv+tMK?-Y=}^bEC-Q0=Z~InI242UEY&^!pR&;TR!MhpOMX{=d~2q`JdUutCN`9E zRJHy+kbwJ+#~|<1$rfrAZ<2tMkatO{;i;FG&H!GWz4dHM8c@W|*b|528{8Z^T~EiF zrP<`#oNG#dc?}_g(=2E^Jt9>6e8)Os;N?w$N2TaGyp_Yo^uZAwH+>oX*AZ~Y_0us~ zhgR>Igt?~1+r59gw}1c?zL$G|QPBQC6z+r#?Zsp8vr>vm9fa@AG`Po3R&OlY8hhLq4Q#^7 zm-Dpnk-s9%0nx*ea(A8PK&_)`-rC9k{1}K~c0No16}D!ccPtQ)kC%+?Y``6(O*=o- z?|4k~0>QinAQoAVZPMs#b*$wB2e})ra{+OlDc>ses=vA*`)j)*s7IE*1qOM*af#QJ zcMy=iao8ttUMqp7`qt_5FZ4AOG9?D}J!($@?xBrj%=}P1SnQq;y7?wX;ZJMM8ZK?@ z**^Tbe*W`|l#p)ungv#WMeZd+qgYR{@e-Wdz}APgrsVjkrk0#O2>#i?SY!XE0z^pLx$s zP2AjSVwY0=T1mJmxA_;foAsVMM%IX?U`}ZU3pTSN?b7rI;Bdw66{~9)(VNIo4xMT^ z9O#kO?9_u>b7cX&s1lg*YX8iT|92FFlmnc!!8`g%qTZbCSP^-1x>}lO*w}hHuW9Z` zvz>lDXnZ)@fiR4^1>HWT@m#)w`x_Mj=wH>5Ri_1K_x;$X-d;WtIB9Tv~gGPw`6$ z>tPn!Ih-n%{b5!j{xr>nH&rpLb4binPG>MI z2w`vAFKj#37eDz^o%n5r6oc{H2*~+<9Q|x?=i~?WU7o-Y+k=U(;&BP45Ak(L{cxt5+O9EUW~8cFo_ zjIUjN%Kex3S5}7nc4A{B!!*^>hGc!U|6L=#pGfBTe zi})Q!b9sW44<+>s67&k#H^s!oS=o+A9nS>`wMk_JnF?Q(ef{}fU?I!gA@zZ}#9?;M zPnz}K1k2Jd>Ct448-p7x<))J9`Kd1E+_qlkT@X+9jz#t2Agfyc3g| zDNW5guLkIG)pj!tf@d7MuA|uUi3Gj{ve40E5#B3{Z6l63@ctAZmQb{>o0SXN$}56k z+wT%bFwE17UH_`}y8+B{QYYY#rTItAJhh~5layW_m|e``Vw_#`kB;;TiYmax?J%oi zPwLi3Z)TTmi>0w3|L@16aiHJ|GrC56MT+#-4)`X9-PF<^iMuZ7 z`d7fyk@7pSKawLxH*>AKwa5m*FvUn3P~lnq5#uqPYV zIep$p<bq{=mQ+GwmQKZN$B`RptgmhUb>|%5C&7mq)<$?G{&g?1+f$bqHh1mXE4*EZ@SXd)~Bj)`>i7rnGX);l#H-v-L z<)f~C?f=}X0R$84K>L#ZA=W>>7&rdFHP{F@Zt8z}uygA~WSOv2Q~-G#24)&d{68-& zS*9oa)j$3nj6hBR*IW?FxF*MNMW?45RbbZnTzy?#Y|;Uev;>@F_xv!Wq+s87;^_ar zsDG~aTi#zO+S9GWHGQ2XTn2J-j`w?(;cz);!K+q9lIg!6!*RO~b+#w|@!458R5}`H zB)xAxLnt%0yC@Cn>IpSJvKX= z$Rf>wVh@QFmhu;Rnh_s=-@2dx*sN=G-Tf?f^*Zi)faj0!551iMC$eIc1Vf*&`l4{B zMpViqL|7**dRK(J!~);GAK!46Vfq|n^FfhU$_&1e+aYx2p9_onv-@0m>SH(`WG3wf z%CzRbRm~(QGLFuEixe`IgtZO12%p|%yH`qmNb^T5Q8{tI(M_dd9M{@i%6fJsemWP9 zrE+5<+%uBb*d3F&Cp58PpXQ0W$|FmYO`2!wuubQ+^2yMn9Ei=V4++hcArt?mF(z}s z4-~@1T#kk8<{gvuUc9d0_6S8|qB8-Sd^n#-VC(0abjW^i_IF7f^p#f;5I}_=Ewh6o z9LRJW5)l8HK&X1Yn)0O+;^WY;un&p7kD7$=KLoz8gg=YoE>)k*d}9d1JG$En{_W&b zpB3D7P2_MIdo6r*d6?_U3)fZ*z(Buzvr^TfdXIo_V zBmux4KG?jd6!w%6_@BC+!s8YTwTX-di%o~hhpxhW$fPs9@X0cH=usaF?=fRu24E22 z;|rME-w0p5ezK$0nQ8iy_vh8W_zi`F1-ZOYhlL%cCT$B_xtUt3U-~*wy~%TMKzaS{ zgxT;$V$6*J<6-B`h^wP5f*k;~XWImK_itcwvB$qeYRMGt)FxFDpp3SPkoPW zQTZwXw^LU8Nsqpky&G^VA^#mo;ddDsT?mOr7YR`b3Dq~UkDEI<;H?$pfBzr5Oo87r z$rM#0P@l>9e-(1gSz`J4Utq?>$FIM>$2Ojz@C6q_FKx%2goPO>^JlujnzeO3meu=Y z-Y>Jg?itDx^)JD&}$9wl&BlJi9s5 z5HY}xbAEoVT0kwO=_?7v^l9$;etj5T3}+mC;6s-JfpkQC`iJ1%!ZGI>+um}rtgj8I zd}~hcBZ}^UnbPrfb&t9~vz$;eB&0tS5O~rP&&8Ri_CrZYlCLG`4Hhdi^J5d!1r`yJ zldlmIQ|jvs(VG4F(+VXrKE({Bm`6oic@6vNN28{K;r zRs=wzp@P*b-^r?-#rF5HCGOg;z+M-Z@0B$4iO%(vF zo8I{eUf*o(i@a5AHon`q1Y>AnsRlA@neet$md8JAryV60h77LK}mBzR0RrfEGP3u(mRia4r1*p zCxB4QQEBXLPp&Gg3she`zQ>@Fi363d;)@q?T)mZGiXN~;Q_a2j{{6f8>JSsCjNSQ{ zWdUBrC*rdB&Xxgk{1aHj>q{yys68;K>xw`}+xj{i4P74R8h?&hLqNpU@l!Mv?|6FB z-My6k&F$jd8>uqp_ayk~3E+l-`CR=aYW_xz8r$`raR#pa)yuyPa5QhN$Jx>n{VgGQ z=7$p|t2j6B>lrrt$r}>T;<2Td6}YjJr=CE^HnfSjuU%qy4KdO$MC_)Zpg?6a5f9)t zMbMtfR!-pF2PHwGhN$JzbiM0QCv~X9#;<}eMaD2AFgnKa$dRjdMo2~SWD%On=JCec zYe;*2teEqUA`S@E6v4z&d)$johNv1ttF6u998N_quev{FrrDNI4A8EnU|cwBwpb>( zCi_8cs51dwVrWaRcBg78^g8teQ1r%w{H8=QY~u~+3A=3Vh594Cgi59>7E#-W zsk%Fe_hSk?>ln@PL)P$?O1D+7<`)q~EZxhmhfC6?%my}h_;HG$$SL+dR4m|yCTz>b zNunM2F4;u8U>7G@kcDiOq>BCBo%EP`*W4-5ok>UFP1y%qxK`oRYB$l$iG=NCG9m*C zZPl%Z%HIFVr)Mp9&U~qpST_wH~R?Et|BVT!yo9BJxdmtFvqg6ClZu~fyN~*#wZ>(h=mop zJ1Ii;e7ffw{bq62Y;(6>VQtg(p@{jQ7g)XvhfIMbL?k5T0Kv&MuC~eHG&N$c0<#4& z`cf6mIN#reQQ`)#vo$?rB{}P?@$2TZq%`Pv{%S?~G-s2Bgo^NoS!xLPHI;b{b zw}Yj$Po!h-@JPN@Qc~i(^x#*rK{qr4|48F)=p6Z(M~}Q|j7<+ywZq7B|Fc~N zv%XbS`5JTD|)(#^#!8z@&pDmA!3` z`Z9lOCpG0pEAPb9!;LA7nz5!*&Ab{=)sL!Z>37F9>3YITOwxMzE6NQ)EO%iQ>$5Dhhk!PJ}gzM+J;h}XBIL)4P-6j zE`rIbJ5}hjFKKe%ppNtAoGW@!V$fYO(sv4WW)B)A^@`!c=0xR`!2*zS{(v%}zZzv( zm<*onh5CK?yxQ@V)Z;+zO~$Q$L5dvz9h$+`pfmIKG}5OpiYF)d5Qbt)EUr ze!8z+9q4HJ7*6ZZG&&Xy55+tUV9Kj;UKq@x-aE|=uvm8lwsJL&vvv%GEbNvf5w;J} zCBFW)v-HPy$NU*(LD!1;OvewzII`*N_VE3GS=I^XIyurU+I%{zBHlz zBnYJzfS}d}8d-@CF!@NmWz_^_XiCRgg8Eg})DGqDDF)=(v*_-5wLX?{;0&*yY`)x= zRC3r5wXJ`1Yq}m;bJRQrgS!a94L#GW(ol1A5lCy|lhow+4+S}aeKU=!bLVvgn?I6I zcj@@HN@5`mwW(hV-zE{wwqigm4(0`n#iM?PlEaOrzN_^4st9mOZ8&d3Zl;)1#Bqo537;HxJ31la zYdIQ@o9f{Oe5R+_c5RZDN)py1c85i*))iZ+ZDBwP(C`M?5FXzTT&&BI_6C^11T@c@@}Y0jHmwUds%v$C$Z?1tx) zRa^JA#N0lb#a06kG7ZfJi+H+}bY*^2^@Gtx#RUTyPeUk}s;b|iz_2c2|6~6Lo2w+U z>2@+fsUzJBeh=L#8YJ0w@4C#X)IDwC6&C4?m*G2qJ7WW+_sHsQmmdyq{8VvD^BZmM zPvVE83k}C0)0G{STTbse|D?Nj<)>e-*Ohh&@Y)+pTTjKppaDtvNBR8^ON^Qu+S~7x zZ3yBcn!JfL(=GA{_QQ&$q@Wjmni>AhGbOFtz4poGrKIcviQCw#oLYTdVL(n>J3}ww z^91O;EU*p(OQaz{uxvL6;zRQ5(qaIy9eobuww;54Mq7osatC&jPZ93MA4MJ%s15E5 zBfNqjLuCLtm&n!;hP=`k2cbG_XLJhrwu~fK?Yfx7LE`{iT#COV@kB;B9nWx{M9)IL zvWGS~qlZn_kXUqd336JvCjUr!%Ocx*ADeaEVb@`v$$va8Ts8ltynYDWg zwEn1ML!KuZj_Gax{CT!1O3Y^S&>(1zoE#j;r@eGvEN1CNT-tw4Iob{8Ol+#A7?}dK zaK<41kmF2)s$Pv9$2Ht(Mo|tsGqda@v)Z)&22WDE8k^B!m2_&$-ZeMA!?lrN4MWVc zbP3-iSAmZJ*PVda{Oalgir!`8?PJJNodEGr%C{;Rjw&WG-96o)1DZIv&>;3MszLQm zat6i5ZTBL%(F3M_37}C~N~7uic{j8lJMX6ug&})TvuQh8&RuV+RPr{y0BIPv83(Us zHaoi7wciQOCw%$^PZY9bqp-lr{6ZN9RMYFCFTl%ey4nP)3+lX3eEU5E&CFGTO-X&Qv{p=`v`6f z09KpIU_n8w2b0K{z=J8HuK-T?cx;T+JQwWbEGMFyJ2k1hTg?B&DHDqqdG zDPIh2{9uzG##XWp24jga{LcA&e)sb`?)$6f z@8>z5r$0K57R+^B=XIX%_xrWw4i&>9*g7F-|G`T|EY@qT45<}obGe?3GR^d(k%e~Z zpwU5@$CQ!_!^p>|bCIQ?d+qBX9Ae{Z`~6buSHlJE;Tfy@%wB0Su1iVrtPy}d)+Kcn zfOkaLv$1b3%gZd%-gEak53Q9pG}Q^$kRkblt@zCGWs)IrcXj%I=X$eBS`t zKN|aN)COWFA|#Y7<)EV5i8*@u>P2_VX2Qb5<{TTJ5^}27Y$FPYfKcp0*KgdwRpJ#9 z+Kmp$EJqK*u^MQ!Q?S~gtv~kzR@Szp&(HCTsc`+S)#P{5dMM@{q*>HywTmF@sMO9p z#Za90t9x&yQ;v?JJkp;%r1n9&b9k19R>c`$l3h64e)3cQiEARgus`obaDo0VBRid)l2o$HPyiGe zFL?5S$i%f*{dJ%An&N$UPOpba{6nAuX5)Y~ZG3(FU3#Ppa3We?uyE?>t<&KB+*90a z9@7s-H5oS)`|1gMc( z1dJET1{}k-VT0@{tDjXL?y4z2tJOb>sE6T_dAy0G{2!VRt2zLZmtA8ERZ}Fm&l(z; zT&^p=yB`ENuo(Hw-4Rgz?M``Xr>@l_jGKHvM$<|Vx3F$LEnsO13N_&^$tU|+Z`GS5oP_Cz<($^po??5$8JkZegLGhaWnWv3 zzKzFtHn^S}+>VSv|MwZyzvar?{9ps7nUhwGOIt=CufN#DCY^d9lKe~?dxF5%=xxCt zQr3Gy8SbEMI?8^%sOgaRr+fT1*GzBT%vxPgkTl~?WgF=%!+vNbny`ZZ7TQ6Qb-&_q6Y{gX^k(qq5 zb;o1un7@7@+wKT-%-$a%M11+%>!tm4(4Phbu-`gl=4I(xKD#DiR(;o=wq%h5u_*V< zV}fsOFDN~Ge;lf2y`jp_EjCfNsVh&5mEtKY+6Mi&E<7)sK9gBc+p2e&`{15sFvchP z)JF5q%RL5eXz4D1JeEv@x0tUXe*14Z}08n+Fns615}W7a&bK~P$J`Jh|4g7sdHj$*X^ z;B;R{nyO8!RVo&ufZBuHedvP*fEc%LkyOKxSIloLz zC+Q3|+m;?=K7de~dWrZLsAXgAuvdx9bnN1Z{Qy!sd_MI=LU6^0%BMvl7q2#6-qKn* zKtA;P;DPYu}Z))*Ototl_C-eRG__;V}za{Y(+ zsv$iv{yuv(sGQ6+{U5>(`j|1pgXvHwchq_G37h?FuOY(dI{1-QXF1i1sF3mPzG}u4 z?mdT*-vHmu>QBz#eAN+^4aKuLqKoDIuo)O|~7JDH7KmtM_ECj9&s&?>g zM%WB*3VWvpOqBC8VSekw2}&MkRn9aeC6L2X}W{FxDOjL ztbseilJ2d8S@2*C^G12U%3m-c?I?f=#d;yDy3cWSy7(!-FHnrGW5GbgeS?D78V@=v z`Vw6%Ygq<}`!HCPfy}jlzaU#5bm{LB1>@DHdD)tgEc{3R5Bl}TS%JOQ+rH!A( zGSBvY8gwu@;2~iD;zyO3qcj>0T)%!DJdn@h{9TOyv4{LK%QY_n7oj6Ov5zUhD#QN% zhk&J@jy&qi%J6mCWnWslyY}YmLt}N4UI(I8cW(3e63{<>nU+}IeDu6>b-qu8G#3Cv zJ}j)(O_i6iqLy&(@iXeTW|~-|>vKiH9+_#F!my%`?jV9UZhC zXB_#y!It~;v3u77cLz8J6}~d>arN~g06L}qcD3m|WR3~0>wPfT@Lyg4b#?di3?G2G zYm-lGQqmcB^rnIDMrwt5DyZ%MW$r6N(zZ#3(D|L}EpMves>fp*R9i%o8UF91%d<659l}Y1??Ay_n>t4ggoM8S+O2rw{ zohztf$hHj``?hew$arDB#>zj6>>qLR!uS`L9y>0)zfK=J3`HEr#Sz7ix8 z_;vwrk~cVw#H_!f$n`kr6AF|^JW0nkfA>5^)rAXgqW|#RaHX^D9nxSs#&JA8wIDGQ z?}b>5>G7UJy*(*bb)+e9Fbp+%FFypqw5er z&#}63sz^K6t#y(FuZkWxTYxTLh!YTY^eh85Pr_AvLyz$JMYs&snpi$xwyP-wqrC2F zJ+n<3`4)EJ`#~MF-&!`5jPWu1mv^twmS`1l$v|cOHCw`HK->5{_v6rQQ@3oN)asRi zO!l_b*)gn45NworckO4xnAK*u%jkB*yVFwUfa@(B6tw2ug{g2Eyv(oUjiSl9kA7qR zL@Xy;*HyUn+&U_7^~~1S2B+#;7?BG&X6BY^Z>=v#P{;L+!27up8u{|;R=L~Zav|LKyzEr zFwiB4Z3_z0<7i*o?oYXag#3O@Y=;eAP?Be}ty}%&wbJsPT}#I+=+zN^`{taD^;dk% ztybwU)18&XT+k#UQrmFrCOIx9v;F9B6>58r^y6(p)w=Tb`f>R?YQLgBuHY3cqix`3>%tQb-&))s{DQC?BR-Kl9*`oU9tD^!JS*P%&@^JmuJqYvlZS;+K zknQo+L*^_Y?4v=(O-c3S@w4A;yFbjX46{m9F?>!wiRor4<`y?U1N6gjcr|`VXzi{; zc)8mMer4u-T|5w5Yge8KhucJr+dvV=Jud}v9(ZDlSgKhDJ?P9^B1a@zye97n_9YM|+ z=nxhdGu-w{n`n;4HnNOqhrQxPD&~Tx>+r7@!#)~lG2|YhT;2>r7)BlR(-U6&dHzO0 zorQ(v6T9hZ$oJi*s008pv;vm@Zwh|LA(X`9e)1W4R7Xu_3`!oN1B`8z5^5Ff*HWH3 z(6-kRNEh{?AU9f0ZZ3QuEQTrBANBORA0@`_1Ahdyat+e~r-i{Pdx|Wm1-UDKMrhlM zQ%{SFS6bVG;y^H2qd+dZ!065f!gHmOWpK6a7JTjdk*dY&cb5Zch$C!l@9$IcHh!U@ zy9>+a1$$_IYBkSvnlXR73Uqy~hcE9qeVj3%>tBu=@lGP~=!*usv+RbsZWe>?B^9X& z$;p>^FZAVP+X~3ZbrO?f#jwI8wax1#An#bQCOO!@DX{u_qSxWh+^j5s>N+eutqxcm zHUW30*kmm^9+~Z(0@U#j+D{Q^wf#(=Ip@_1O)F4?L^O4^oM#AF)Wvh}t{YDuBTTFw<=XhO!Y9mt>tTzAT_Kh@oYb3F6t`SLf-b`YYqFRL0gTu<_oqhrUuBfkS zP1(Ekg70r=^kD4ut(@<<>F>%zwgBtcjt>gDWy;2Vx;$fQPC56$2E{=RikiLIG)KYx z!4|o#CI?Ag^K;$xCA<30zY($fvjA<4{Somy&Y)@FAa_x!$sQcBT3xVfCXO6?6{c~I z)sc+?%vD+pBDjW(_?7+cH$`nex)n|94OI90{aRGiaPW$9UD;GM^E<)kO9~t=(!=B` z{}+wv>Jsc~t3+Mzu~eGG24$e@dv)eOH2=9JI)4>|7^@ zx~ZSm*ka2N03)2*#GJ&p-$O^v<9F8F0cn&J7_dj-U#nR!qBDF`v#)(>+Q|Zy`Y2={ zgZ$U+VT!~ci+=o#uyj+gKq|`hp~J$ETz5WHu&a80=ov>RyV_~jMDI@>00tc#4|wz_ z$vgdl9PUjtJYym506q#HlX zcEzeFmREV%gUm72tiUj4MSIU_9~>B^#ytLhd*DbAn>490KOa{eS~gtdRly>iC`VY( z#eCu1ib|K%l=U|sQ|iRJmmi6d=O^AZ@*3S#d*0&eN#%zQxq{hW{NwM7Upd#9nV4ES ziLZ!jo15`wbxOwz6X0D3WyNreoT*nUpFMXn(iWjqdWZI3$yt4upxIrbC}NNnv!Bte zj7qu@4{!*`lB@vKYoy5i`HXLQ0e(mhqWfz5kblx>v`G3^Y3fa5ew44*4CTSPG z>iXvJ)U_yim}G{0$IVh7p}IZlafxF~RY$gdeh-h}d}oDnsk&^1F;{{vg44oQS75e) z!eI6)IN12G1UdU~Yo*AjCNdlIrfNtXsGit-f`4)PMIpqL9wxL}FHA zN93KlndlOCyzUXA0Rsc0%hyr2i&<95@jLS}LGp0CM3OGenni;D%9vj2xm&^Lg4~58mIi3UASo9uMa%QuEJKdDWcX2(5S~~aW?A! zdicV|%{X`w4YU1=;&a-xxz3WtoO1#v3lin!?ffwDz*=`2@~&#F<{9>hveOcJL)CFw z{EzeSwCDW5Jt9(Ou~`q!!!}$;S+4_ts$$*kI!xY63V363XgG;_wlu^4rjnPlE zdE$wzNJ*EvdF!F1H_E8}X5=8`;q>%#_o3VmqWimtdKX5&KF$3QWM5L(F$V5ZM9(5Iq;fav}X;vO20QDg}3u-&{ZeHJa`0Y6KkBh&7jrUl%-T&;qu77V$x}b>nYWNryEV4gR z5vXe5S4(m|TLROLV#_*mrDx=HEE&li_z*@Z`MXHtERw7v`7-e(!wxSPfn$eNu8hGp zEHHjw0NRALFFXtUjXDTBnpH+|!jXC#fh7xs5+T!~n}QxGD!zsQ#Ju+*H^*I&W9h`7 zXRp%J(iU6Iq5ZSDMR=!f!wuTu>Uq(6|2!DI^>M3p$`D7!8hcn$J7&SD$BZpyZuN#; zGjk)rduUi*7s9^U-0|8damYTZVH3ivuEUHiZL4iIxmTgC!FRzJ?IqnZTm7uvB#bh| z-QfEm`(mBfa6>q5Xn3%*IAJ5nxcW`P#j#VUUV)8 ziW}n70x3@8OMQtj@}!5mwyUk~`XMQ)F4A9l>CVxF3=UHcxd zB0jwbJ!<7drvk2KV*b#yEB7^_b+EZXMGL}9?erETbij|y41=%GvXdu)H7ZS z@XWWMeRxm>cyG2-?L6Hjc4B!JH3_&|Ao(t;5IUTB8|nn=M%A^?_t=SVjstCkok+s` zPdk&S;fa_+`u5#@dybdnMP~q(Bj-$1CgTm==`{f=+d^fQm;LvRbzNXCnGn z3KVG5x-qbWU50Wt%{zGgth{C?niE?id9d_0Sgj7)@#Zl=KXqqqj)yZKidRlM@XzBM zQTO+kD~3HIfOGXoueF+E^WfLVjQ-*vc0y_`gB>A-l%d&fAFNk&*C*ujGl96+XaUtM zuvC0jelQ+9nk3bp=r!FjxU>1PzK^RDdutEoaj?SS8N?JIy0pv6rrwTvSi-c8-t?3c zvlMyZjZeWJYHYUUTVI)Mo5%2WO1#YpS?#v})=EN>om&G_V)YR6TELaet~2A>`ZHyp z`42t0GR}PxmbC-A)m3<=-!!{UT$qbTAlOP)C?J?#ix;5<$p02MfLUQ8kj`t%dhAm0 zq%3g$(>260QnsH*nibta!1m-!SLP?0qjdlvV#(jBvuW>M31rQ#_4z^ZWFDkm*Z`n9p-ff)iz*iAwTT=GTX{lmvTYcjLerJW z#0eJ$MCjtM-I#D^`xXwNK=cOp-itqv4cn(8^$^BYrAKV-kYG!hNt-9q20L@TpP(gk;8S-%4Y>U$`<;T7 zM{MI9Y>5z-q=A8}{#)<%RSsyG-MAj=Y7a|QDtBG4Ud({6nTn}ZJgo8Ir^|W*)(59^ zba5;-Bs~S+FSJDg$GU+``^9t>-*37X%xJ%~OTp;Io6looJNQgb(Yg*OU9s!x5~U7! z)HNFDWA8+85r*Eld6$^}Wm0)2Sfhi%l0O4FhlL~r^mB1?+Q>|KqnRhsXC;F`Xn?Y= zIA>aRQ;PiBst9$ zn@3UCfH!b|U>}Rc#KeTA%ru{@V@zHn4wxIdR`HHB^CbEUf{>Yr)x{Aa@8T$$_@T|o zR^)Z690WymQ@jF+rSU_D&th|Oc3k{*tM3<_azZYDJ7ACKI3D#EwOnvLl71lsB}&JI zV!)U~-S7dD)EL5LplaNBHC}tv4WEWC@!t@b1-v*waJ*sPv3(7U_bxIrANlIe;OGPg zoN2fktQv5MnCL2c2m{3-+igTixZa{mSD@yO-}?MxzqTsSB6cPuc46)1T8g~KK)&!L zP!Ia>XPHoeCM%BUUS|QwK<5G3x*9e6ZEKD1f~@R)z*4XiLG@wny?>cH7!K+x`~UfL z(w}}#piwnsOxxne=_L7un$y~=&u3md*n4LS)?ndU0wh1I`J-VSNua3ZS>??jWYk_! z#=%lK>!B#$?+(`18El5YjDkz@m_4C^SGi{OF)NkL*@9V9SxFrbN#Au&Mm;D1nu>2Jr~eg7NBx@TCuZ^Xlqg`@LN5zy*rwXC1uTQd(G zPHl#O{aEE4^O)QX%Pg-PT|bA^#R>62%Hn4e5vxAe>W-eRk2k`TwXD9kuZfp)qUGsI z$C|DZ8Q=2XzfX8gcpdE^EpO%>u!;d{6)^*?Ju`X2l3 z#F;RRq@2zzs{^=9CCH3dVmllzD~*+vw&|{M)9t zj{zeFR2NV{c-*74{ddz}dJK>SwE)T~rN4cbU^4hH8zcVBEqfv||KJIaz@&kFOy$*{ z8U^}89IpYm4Qyjn%5#r<@b4U7kPBEtd{>D6xJPsG?+X4?v~R!P7#jNS^d6J{e{NQN zIDP!TgtM9X%bNfHZ^<6-*#8Gt2?NY-9+Vt0Kz~5|xd;kxP`HuAZaAd;b=@4Y`63^XE?vE-qm#mivOZ z_(E)l2_`_1g-u)th?oYwRc2gQVW zgFnA{b@iEI;C5wuilUKzn#!bUI`KLXhFmyPZw1so#9<#BzQ64N8Z4YkTfD1au3uKs z$kIXLcBleHx@KU_r_4;cXjs~3{t;c4p*ptovm&Cdj?iD-3(w1-vh{DKSzZVvA?Lt z6;PmspQk<{K0hk&zLO+WDSD^m;1)#taPZLOh(^?{tF6)@-MxjC)t`>vHP z9vo4*bFMWJBo6i8v9^v;MFB)o+NMdDI5yr8=IXOk>r2rcp?dJOgSfrW%Vwxyw`uOb zK9uESfH#bm29!Iqq8fdXw+l9XghDeB06mnpDJ0j!fK31pr(JTur@a?7${AXFxt4z| zYzyRupO+CWth;&ZmUfMg>*PT31P3>_1H=6OZV+}1n#wTH7S*SDf^X}&OWV*Xwa3}^ zed&Y0I)3tjkuw2IxdIhCYS}z`-E_3H5-ibv*iV}3gKuotO#2I|CO~rTR&o0_S%%;( zZ=}AbSmB>#u>{)>1V9kxP0;ZyMBflNapFSQ!LdtgbA54OHN*R^eOjCIPSyXF{NY){ zV0nEyXknkNeWU?nqJ}`ad?0n74=BEh7IF>JQIoD;?&r;!PG1I8^B?p)I_>s=Qq=5) z%As@T#qK;?4K!QHv8eIMd7=M+0!s%97LzOHEf<4qpuhiqZ;SuAxAv)^$@=k zgenjXg0~tHMiGRq7LTYo_qw~vqm5RYyzlPk`m{k#Bq=#T$o_5AM@8XV0Eyi73QX5}>bJG^U2Uw8SENgD`x}7JJU?5QwhUgj^QQO{m7%8 z5D!a{+ZGrVDpMYSeshin6o@~~1ihp-z{cjj3zmjZdwa{S*U6ZnT;%1ZiA29YK$lfv z_e_?E1|2IfG~=OgIwU9$Qs%(uO;EP+M=Dn#0x9G#8;7|ay=YkO{D4Q*@7;`T@y6J0 zFvv{7S$Y9hRJ$32oo*gtroduP52t^tgysXf9Dd^wqtDq)hi-|O@~f+5j`{;X%$#ko zfOS1;-u|H;9Ego4d>-w(=PS66L{}lJ_ z;pbyctzBjGj1nzV(=YH|pD0l?uYsc`$cC{o19{gW7m*SG1w{8Et;U#FcT*vVG@$Un)R?1OF`jT=~b5 z#lCPYEg`{;Vb$rA$=XXrMVBIxj*_miF{`p#z3bPXB#5Wg%{}s-=bgb1mHm#yuw}qb z+N;tErk9(@{|sk?`uW0}lK$P%|NB<|wu){d^d>^}UOO_jO-y%xBr6pRJ2_@~C<*q9 z#Bjz{zq7nqgc8ZJ*zPq%$R{u(6xyN(=_rtl{(xhc|p5Om;48gDSnGqlsX^SYv8t;%bv1#F(? z%|H*P3DR6`!{)%w<~i3Z>K{d)uEIbKm}QI{?fx~y1y}^e%zJ0p);?*eTyb6?eWsXl>QTt%C z(ssH&&p%uZA$_Y}>aeK3L*F@oqhf0Y!rjL^e{co_ro;dQrmcbT;LWh{Fx@j~vx-G& zhYlA)V3oLIr@EAsmfH3>4B$(}CaYi;7NaC&FQIZ=A;~ukm`db%!?kkMyL!YsWi-OEGQuX{4E*XnK zQ?styW`UW5qhxiPH$m&i+mo&yeqf4RvO{QJwx3F3X5-Ut-#O(p_7PoRQTh-#N2bpH zNup8hKrO*x9Xhe7*Vg5jgJGU7&%PjnppfIiguRBGKw1IS&g55?Sa3=aLy}HuX=}%} z=A=Y2&y?Fn)}^O|;;WZ=!pO+TZnRc#5_qLLAa_AqFYg~Ty6XU#;rZ1anq>94>(}qx z`FyS`;wG87M;Rq$oicD9r|1-gN0VE8-51q8c0%IbA)qP4GO+`S)3%Lo_zA(0uBX2? z$o3RoKYr*e%iRMkA4f+w+i^ql;;w6vS>hO(8;6-LgZM8Ey@nVU33BEDZ%6^}*a{p+6A#P3~Jm>R~y0558M#2uC7C5;C zuFTHz#6FfLt5a8vyl5vk$~$hoVX22Kp}l&>{{U+=^ihL!sT*$a_B9M@e%>Xo;Ijub zJt@tN)R`C`KWHqPK+c>ft^K($Gq;(YCh( z{Qbb(ue-nBIgFAG7EhqRhSlBLKffYWuV@o}=iiqY1P5jXaI`b-eUPNx3E75h3SSkx z)RSvafkzHfsvQfAE;Vs#mNrf!D9Lgd0#i0vf)}LEb&q7{R1YzIB@R;=2b1JolMCeF zn?QzBI=DdNzrh_eQVyx;?d=^%Wa(Jb!|8Dda4pVP2SMZmN~7oLaDle7>6ZZ8sh^jR z@tr>Xq;xJ?KoOwasT{bWT|^#2(8hVj0It-hYMb&6BgN4)z1XRLx60w#*qXt z{j8ZOTwwGk6LR&ye3F!ni*TKTBEp%%7M%1{%A%?FfHN7+&6?)g_3KB8N7uQ{aThHjvjh;D z>g43KGU`trI`BmGV4ke^A}1%Oki2|9?0LzR(~y#1Wcbjke$Pv{a?}o{F6iRqWYN}I zhoU&8XLR%|i$KKmoX-Bj$5s|J$M+VwyLWc=z)}dh-p;=FQn-cIFfqwvF&v8nLy0^3 zZiIQ?1D^|FXS!@`T;3!CyH~h_^kTVwK+Nsbt&r=Qnws!f#W894Otz<}1im*S+H2Qw zpE=^nRx%vkw;-Ny#lpUHl$|yqh)ToAyt40s^!)H}AH58asEVO|HOwmtE&~^*JJP%p zySw~W@M_e8l$|Yz*|}z(^TJK>zDU;ADc*EfB8uoB2#InZDjV!gXHWe0?Ye)u#+Ha| zjBuOz-ml_6w>>pZ99S2BXtQ57wi0hnNmp|H0%F;AzuUgA(7N}Yxt5g{doA6mgfj8# z$pXGNeY=sgUbm@UC$+X@X1o09N4GPVW1puAX6Q?<@nHS-qN;x_2pfgniaNd7EkNBK zcPMe9*l&(*)VVjg#E}R{-@ZI6R6vy@8})&Kx@%BM$SU6f_nl3=&qhn4)e!IY7;O}a z`&4;NxD8`I>c3$@VfbEts?baC%=Xd4?9og34MB#VPVkA>+^5vluJMu>$?93h+1r@* zxfWOi$7>uhSP7;^hAMjpN}a$trk1Eq(3fofTKahwKO{JK zDJ?baF^FM5XNFaoY}R17x%HFDl;eCNoFMzL^mWPki<$-%(^ z3NO~cT-`gb6@JjnCU}Z;_IR_!-)w=pyNM~Ra8WdP?%}O4t>doYL2LH0SynIJN3!kv4XrAZV+=D6~ z@v$Pq(|CeTHj0+e*3_&D`13Q|qABwA>zKZL!W|zU)Q9*r zagE(D!P;|x1@(bbBnrx7z~0!{c*ov8$K=4~+ur_a%frCp4_9#W^ab}i8VV1&wbFo% z69L}kfo=NBAc=~+vN=CU30)hha38x9cw}lX7oH_17RPQ;wh+wWnX$G^bslnE>h0zl zLD!oOoscCk)|u???X{I2L`+WMt{Y7W>jKNm$-qxNx%ifjR6G{Mx@a0N;M&^aS-H2< z^~ji?-`P@og0_LPI9P@qxy-dliF3en!$D>xbssJGAm4s&dpkR9p_$P7BsN9SWa>xb zo8yvVIe)#KM?#MCXW+5e1R#9HegN^?8+E&Amer=#iaJ_sds-?m$1q2Q^0w^EWJdqa zRj0vEoE(t_4n}9=Xg}G59JNU)iQv2=`s*jlYNh!(XPeZ^V?SU-81KgznMFN zLvCZ3(tRf2;lmtRd3h|TWET_|>^o9K@#=ML>s=1DPct<}gLYvXawaBT?QL)EavBY? zutWIe)^F_W(UKvwa-gU@VWgjP<1ni`=+STESR=UnY2g0o+`03Wps?REaMLdDOSM>f zP+;de-72R&UEQiFlFy;;{nBKjRSU?aTTrCkp04otd5$9fitbTbbXwJ~_c?bJ9y;3T zt}-JB(n%A+2SZG!-U!CXa8UPdua<7IzMIi}B6r@hZNR(|DCYyZGAeddHik=ABz9MJ zTYHDy{Uucp>uzYN(&8(6jx{xf=pPu?YFW~Mmj zChojF?h;hB=fIoShbr*&>8q%OMB?!9X@4C;#l9=m?#M}hSw>Y65yDlK7?9L7I9}m% z2n61NDHyiEM8>r$RVQ&pS5l=dAm2K7)A=O{qa;$k?4oo~yeHEYRM0*}yaVbU<2F>+ zm)w>E5KQ5?lDhATtqeYOUFPbunV3B4*csqnB3HgE^8Dy*xhiZ+7LqB!d-(8S7cQ8y z^A}@5pS|0}eIX(y){XX^BErJ0-Pt;>^40w*(4odRPKJh_ZM`zc_u$acx^=5s^(07L zrY-_Z6&TI9GmP4G2;ErmAFZuIUD@#`qeZ;E+2>WkEiG+PCDN#JE3>)j12>@L(b5KQ zoOYehLNZI|^kCxAs;a7W%@^fkV?mNX(n&eg@n&{QclS3S<9w@r<+i&H!sFD8XF8d}@#LKBEVSij}e7=kCM+0?Q z@1j+er)JxjxT`mKapMSxU7XCy;RCMt2bJJM>P^y;y)}MZ8x;677gtMSu zcRMZlN@#wAuWK^8X#bzj7YTB_FBGolT+siRhSDqTFLxTRlMq+m{ZhtPD!BXSHn2H* z$hnG_Z16VL60rDf4RWP(0y<;|fnc0ASYlWDj-T)R^767;IN=?QF3;YgRNxd2ebQSG zd;z=n6_9Qa%Vf&AqkETy8tDgQ-E#Zn97DtuV!7zP3+Dl(GM?du(sOO+Zm-+T8zCuJEo{^F=kuIGYtepCJBmJ4y{eEwO zwE#oIwkvODK zD4+X^sau3;PG=L1s9p8ZSsmMlhc;V zZQi7c*J=n_$d{d1hl31@fW_dA$ZP|(hV;vPz5@%Hv!_qf$`VftBJAc=^?ph`*%%_b~m zX34`(#pjX}roOBdd3EQ6tZBtbyQs7M4uA22xAc_Rh9#a9bcDBE-EZ~v=JA@0{DhW! z5L^@T^F;;L)`!59I52O-wI@-y!%L|-Wz3Y(il|K9#?gW<`Qf=OpI<9$XWQ?0`|a3X z8==7$4Q=h@cG-}1PtGxfW9WoFLI(PAxbTbQNl~}9m6HaDm9D;=FR#Q#Kf}7ayM;s* zA9SQCJ`P(kF`?kL;wk9RxkQQS0S*7>H?sf*&W!7_`ID{mXKs(5ggh4R=XGbC=x8`0 z;|765l#(dWprW2cc5m-;`Sm30*so$L+OZ1Bm(J?p`eK9DVqYLuMyoN?+Xr+mNNn(l ziuspl+eXjqqk+_mh3na-zwD+vrso;*1_uW%LMeFFjTGM+LnkhAJ;|VVUJIecYP+G# z9+DuM!QR2%&%!r9>!yH;M;{!j?>O=Y#J06WNMJ7d`X=g51%-;UO{9?9$TiUXdBg>A z_RNVfw0{Mm4OFOoeSIa~BrZM;LbnE}mL>PEX;;CBYt81Srq0}6#4-bR%^*{s{ zr%Z?12Ei)G6*5TNFR&AbK-iEo<6y(EftvIPI3!otdGdM6J9C0y8gtE(Wv z3Ebdv)sHkwm|t}dTPU82eg>vV@+|?NP6OG`*|_$os3;Vi0?dCk@2`7~G zttfYKJta_Y5@^WfBEBt3^33_;ijQ(8)rlWGdfKCISt)2IrSNuoyxi>^UHByt{nH@R zxp=WSnqOIX>)aFaD0h4D8EWAHi|q%cQ{}VM8Q#A^%KIg7I)Am&!D6v;?vqyrC~3R4 zcC))YOm719Q;G3n#tY{vt3BNG_4TKF=JzBxEHxf_#@*JwGnGQr2&1H$#bb*$T(DSC zVYAVb%@mbI7f6YVnOTkT8@RTNTMo9i&QlTJv}I@{q8+Kl;O6SIpr|p{Oe%YFJ7Akh zwA#e+i|>n;+RX@;2hk{bf)b)*SS5&5!3;LT$E8#=Q@@Vi8?{$DD{enyMu+7G6>Npy zchnvL>Y70fbefoiLJ4^l!ht-01w+MCXN=2;sfva7C8^sUu)8r*M zhDKPMcfdb*ruVRkAE)G7(GUbFwz>4HPrvm?cXOHw=Xg;k1b1h=@4)E)ZOHV2=`@;R zd~axI2=LTl?7QbXw^sRu#ngzZuR3moZEp!iG5=ByQr1vT1IaQwbT^{fLFcc#KdTQe z4Rp5q(w6(&l6TLjvW-5U@U|Mcx>xxO3Rl>%Bo*J}#-^x5qycQQPuca!D{+2K9>rVI z(!x5ksT@#I=Y<)jO*usqomt1KRD=TS1wWT}gsZ90EkBD`U#AQytwM3+7<1?Rb2I_a zhn3i8N1^?7y^5R}(9(A)Y~tCUuGzubN^HW##4Na9^d(c0i`9n3&!7MPp<*)u7fjG7 zyW*A)UlJ0k*s|!*$=v`t|n*u<>{IngUuR#jZXrca*Cj&*5rbaVkOW_OHC zbMEJ?f%hT9->L{y`v7-rUB?f!MQ;3E*>U8AqBmJi>gqS!CP+znlNU@5_A?`1jXAb*9#X5J$R)Yo z&!F?|VX~4=+Vm?g>aQOWpVarJP#n{+KEq(jl~c5Mts-%5D3-!~`8}~hI}3%n^~q(b zYT&@*8gxrDOQ9Ju+g2DZtyrZ9GYDQ>sLr||?%s2$8KdM9y0Ea`VH`@aU8u$Z+brjj zP4}VSq~b0cSFKbjVGs4QQrLvSDvzCa(eS9n8~b@O1V;o}4E72T0c+CWOMQG>m8zOw zQC@*pdqf5Wb4!^UsmTY(=9z2L<+os(n)tzW{h(>60l{f7K;ppPq2s0H8`cy|$P4JWT$n{O?R|E1*sZ`VvFz|qvMcl|}APyfOoI>#+n*ygV=+L_MV;EG`{KK+#? zvyWlt1b}c1^qTgDIOwl=Ml`r$>LJa)#uI?|UKD_F>B;Z*av%Bk{%Z(=E8aN%*6r`N z?T-;4dn_P@LU{@=D}KEmdwH{4_#IzDK{2@{{P9zOiLDUzWk_5J&^KYsiOtP^D1 zyECJ20Ftpx*MY0kuJ>n=)zzMSJIWNUyR-8Q2=pj%?z;ry;!q)*U_6J_kwDw#oVXw) z6fJRA@Z?Ex5Oro~HFjoUVc~{e=K>7?pI2O67YvOzGKgwnip!PFg6+erLoF>Aom`y+ z<|WPlGpZP@PmQ_**T0|3$}9djMtIr~CkFh@FI;PA5Y8dm9}BHL)1GHZjB)4$IWCqD zi_Aq2vI~5epLd^Un#Nn50Vqp+ZLNyp(_fXUIoJFhY6!VAx5EL84J0bZ=_bWEA`L6e zDzt&5no;I@1wi_fU@CMEoywu*O1hdnGSi`6uWkF zXMY|pe43t;;==Ij<)U?E4-HTO4Ig+DQVfd2WseE+tM(^+6BQFnlyNW@dIFd_mw{Kb zv=^>ozdM@?Dalmn7BTby#crZ0((tZ_#nFK6;+aakYDJIjOmxNc_wV0rhby11fVZms zQ>8+?xmznRH`V(Z7^#Zfy?OgKP)}5j)WN8z6lG`!EwkY%Tcfe@Sm`w2_@4tDFDZ&L zBy8KJ>1Hdd#C-Aev#1R+VPF9`ASY8#0*{d8H9kg(+OLETGLZBbnwr`(Qnw7hIn90b z_<8-!+qbdcgC;q!Dd1OA)}C%H?K#`{=g8TmuPvle@4KgkX} z)Kr*^Hx6{HSW5>BjkqlLwMeh-tR%=k>M~v8Eg*0Kd{L&GJX~e7F)_i}4(nO)nGOQ} zxb4@ggw~gSV~uoC0kz^mMh_m?MZ-2HkIU2{U7KnJIu+fBs1XcPr{eFasUdEGsw&?p zmvD3wVB0Bj@bH`s+H6A@nwdciUcO)=a$n$GCC_+>r{za%25!xYtZ$FhY}gWtEPO&N zaKCc@dKewiwSL5~3Tj-`iHHQ7+2L*eBxsYnk?CyOjmg{Gc~nDr5cIv8yd3LZc-5fbF#&E+pk~WQC)D;cM??12-)J1$*I9_4xLh# zZvy@yJZAm3taz{LahLaT$id-oK(L%Xx(Z1^C*;o-W@lYMIDGazI9*<6zm7*JSaERt zTA<8I;R>M1lqZkp2OOu5)$Ij8{ZrpCpOO5%-_PRD1D%0qZa;n`i(6jSAMst7c7ZM` z$G~t5gpBfj*hZghCyeG7Ldc7Xx@|Ju(16L`@4IdS#ME@Ei9H%}rsnfZ8KBIKKy*i( z+=FD@65~>j&cMpEbRm#@?33Mg(tMg~jV5wt>snf1yVW;7{z zBJg-;tdf=%w!{H1V3v;l^vO`xC}?q5(Py_?sIYIbMovLtP)#S{GDzyY>${ZEpOE0> z?Cfck(cBar9XBxW$P5w)q3e82J{U*a@4qAvlSLkSO6 zUp;WoAp?Ee{9|R^0>sA0iVADSYp1I^V5u~9^ode@2KvaIi9nz#&D|1@G z<~%umjl3d-ar0UlzgANZ0a;^M%k)dtcSyiaao8gIw4yVYMdXL{?ccff%L9T*)Zu68 zd@Z*gK1`^(++w?6Ajev|=(7v5a@&|Y*#(ts>y9rCL3Uj_R3&_UMh}Wk=;)(9L*1I5 ze0+#%{!F8dW)vTH;+e>`@@Urp<~^O%GL%DFKA+0VE1FxBZ9YD8E@OGn+UV(zlQQc? za-$ZrPx06Osn7Z-^%Fz=2TXOewdb!Fs*as+Nr?6B&86&Q%7l$L%LqN$>ah%1HY>5k zKFLEO6Q52znFP28DxyO`*{7XUm5e~R@^9?CQ|-i5-zg-0C-106^ncheZ|^6dpB*4`-yw&Y;Qy<=?+k0IZMT$eLsXP1 z1PeB*^db;M1(l+pA|0hERXPMhRk0wwmw+@8gwRW;c-s z)GKm_QThG;tBxSz3ODjvf3GsQZzn?JxFTuJ`wZ=XlUWoR;5X@E{Dw-{`**<77yu$C zwuG=lH22q|TvZ@e3>LIq7FzrOoA|v#j%BIhteqx?ri3gVsrO-8xK;w#8W)AolS2}t!TUL6@9 z7bU6rxG>i4(IZlDv$tr>tiZ?Y`wt$B0<|94*q-68)uqd*pYEZly`YVlpPPUERX*y| zEfg9U7IsA5W2p$+X=r3vyE(+Y1E!Yxo=qn^^`SNHKk?Mo{#0P;liO;S8qXA~ed?kr z>iT!K#0%tT5GqWxr_U=@FipkNUGLET$^IU^?EkR-fBs*iIA}QqVRmz*y(&SLVVC*u z@lZpfa4`q=Jg)lq*>Jadd_8|Gf~nC;KGzBE-x9h$sXDP>}df1C>@E6wCFU}zvbrU7Jr2%paev< zPV`Mts>tZI*h{O7E7BUPi@r{5eIrEB1EIajd8!um;K74-fMvFo11CwMAsCi~Q1YC* z8MwV!xhMMm{rkGjY#Kt3l)I)f-Mk;L3pyQn_>qi)*Tc_3Cw}}mQ(jJ3hObQg)ear- z*b>`9*Y|yV=`_iYuNkc$Nl05;6&^#+>YuUocq!sS*p^n33ah zCr`$@EF0E8RU!k8wn03F7&SS06fa>O!gp5K{*lV7asF65&3lKdnt!|bN?Ic=GV(E` zx~gi>DO}lMSc>>v%A5HGsc8uaV|>W9MX+n21O; zMegv5g+)uEi;ZHCwkX`hm{PU^*upmy>nJ z$`pj?&`igANie;VhVFHk?K)MW^zu#Y(0dE|d)6IIPoLLURec+4f$(l@xMv)yRVV=E zWK-C@6`^{?>4 z?=nxWCp{r}C!slv&yMpsE7*0nwiw&m+hc%3tq03_TBJtsf;&4$-hcS86-e^Ue0}-O zjfIyHyz_mWMdKYoKJf?HlTKQ?pL1SX7jhXogWmoVl~cVxR{4$Av+`E z8c`gX$j;G?kp*-QgilM>DLYuKHHi+>xWnl@@=?6a*L& zuWFB?th*JZaquC9KyRDKM_oAtedanOnRVcbg#$;1L*(YBhtC~2F@54V=zGhiIh4Gp zCjI^xJgusV@!4l2U$3jB3$^K-sV5+D`KE1N{!LudpZnoA1mxr%1*u)juC8tig-pA% z>3z$_$_R6>D>31eY?g$NEAj;4BO@c%G9f#Uz>XCOn3cD)K6y9z4oR>VImx(hLY%z$ zbo44{+wN6kk!25IqgT4gcx1}-Vg(Ynw92Ch-RjR|B{0^ab22Y7fi?ygvNL z9<#tN%yYqHA2kv+Z}Xomw{eo>Gf^Ax-=7^e1!wOhD>scch+u$$e!xXsmF4FAXYf=UUvV$sA_mJ^GSb>) z=om?qUZxY4#?+3Rzd!pw$|wSEztzO)Y1m#|f$>aBXffOI6DOn;_+NjVdyxL2z8Y7y+HqHgY^&*|T@veL=goIh1XA5(Q;6djgGbCNI?f%m^}_jdwK$pq*mD6X*m zzjTooM+p6Y1K_*0GjnnbFJHd=%I7xKF!FB%abSz6xIG;Sy$y&8Wy8yj0Zzyo%CHYlC$Ozd+Zu323Y^R(&$Z7gmBz^#0P z7Jz4*NrP{Gl9H7rk0~m^K7*SCD=VvgAYXq+rmnU13MEA}RO?*|oX(cf{CKU0X_NhQclb;xvK{JIf8gXIRU5IZ{Jly4MPQipPmXygbCQ zDK`MHe(m7&o0e@LzNge5z^gR8rq%?jeHBf0WRz`8O-MXT(6MZ`Hm>~7;qJw$+3D%m z)^H}JqBfQRH(^!VH+Di#9>YRSUB*b!;Ism{bw zkI~M~p_~})_aJF+Dr(a1s`A9k>&0i2nuio1;qo${?jtX?Fp&0|?Ri388YR}skDmwb z{;c1ft}V0Hj2njprKP(NdqlLqD8zre7_I5fhpej`Qx1>AgVd?_7ITZKLau+=iEhwi zZmD)dvIC8ll~G?-QeYb$x(w824dH*jb2{dCV~eO3)W8;h^%DK~y+18m{f5cLe}PXB z0C}PYiZ9s!0EjOd!_>pxn=XduOm!t(F+upj%6*)NL1k?)ppN1gLX8$H6}2Q6Oska5beKUir$2tg!NgZ%SE5WqQu+FqmhwBD%YWA0SSrJI%>L1K?rKPUd8HSSz#<4l7WS~HYGLz}YViQrD zMoaHrthr#{y=rd0N&MZ!=5XG}(Xnv5Pi3dIzt+rBvbC@8LVMP&Xv>NEhLOW=bx!W? z@2}!JB`JYkcDCozeJQmar2kI7V!kPBSw+pbSt+r`4pdNf9zQUzmu(P6o@;2#HICW!n(AvB!XU!W*nRHR-BA6_M1SV2Mbz>~RWB2-fog5G@v3{~=G)X8IyQ%}aWWn2TL1Yt`-Q54GB#S^46h&H#X`;W^c);aRF~8becNO#gqO=> zH~TA9a0?6kgP*;-Qm~pZ5pT)IUtc(uti#3l7Y$>v?)n9ULJ_I;V>Yy=!7-m0I@;zq$&B`C97s^dw zBTs$2wA#H$FPH7lqx7%@qp(Yw>YpI+O#ak%dRSlhlNQBWe3 zah?EAU;0e4&%MPJk#t}$m+8%lB90<<)sPzMwj3Wf%Y)Vz*;Svas?dDmQwij%Ze&YYMK!z0l7@|!%-S{+JXFdM>lHE++PjYwx1jm!p*jH@u(tiJ|2jI`PWBU?~ zkaPYaT!`wzIEsN2xYzCtugS#P7=ODr9)Sa~&Bi9Xh$ z>Jx{1CTqqQhs%B01=1|+3L#hLU>u-gXky~Pp+EM7VGLEZ1eh9Gd3m~y6CML;1aCdp zyJQOSg#AL!NV=D+YqY+;$c4;_gFT$b0L@0`-OuJKw2IeV+&F*htGM}IC&{birP8(U zoFQEup*O*~TIWrSxa_~xw0dK)mu!o8IBZs+fV?res1Qc0l$dE?uEDS_FFz!+Rp*M+ z9%}G!IPe2SKaBeQ$p*-YZuUkA!QM9vE3Vd_1)>(w?snKD7sZ18aTU>L8Fbi8HA|R9e|d4Sr5sKy3U1BrM)&gEU))9YgZ& zBC;WF$sSw!^zP0-_|*ssN27VA=!=_4&wy*FsH`-LsBzU(a3dR2GgG%sdG`goH=&_r z`0&@S%ckayTf)O712=50b9xQLGcY_Oom#EM7gB0Sej}&l4 z=?__s_>L~R958R8WfILiw=R%8*ySSpEjwz?-@@PuZM#Js~^2VJm z04o?Qkwfh4V)sbdDGKiGF@EyrEt*4*vD$ljLJAfO#aLj6I(@>BBQP@&iz#8uFtJu6 z;*%o83Q=4iqHKa(SUd**a*Tt+x;{32itGq4UhuUtHV%@)U_F#Om8k|0;U@ot#{6V> z)t9+rJ-V}BPJcN6Fh5qi)-Kv^yQ)$qi+f#xoAt6?^9CRoSPkUG%5bg9-x9eoB_ugo ziZ-uQR2X(}AS0UpoJ?6AH49!r9Ln)fMv|385P3KwL#fvBJxq0(7WSBe=5xR2f)1!K z;@s={yL0F}FY6yE@uZ4Sjni&6K#h%4w1Nuq^41b3c~73Sih7=@C0vS$OWyqWIxK%` z5f+Ci?h#;rfDnKDwW3!J*iKWlz4Oc<&_!tDE z;e%+APXj~kCQHgtwc%L<^O{S7sc|yBaiFmn(Ix(q<4C;;aGtC?o}1M^|Ik4Uy(bhILw4s)0!^?;*221*akJ)xy=sRv9hx76V(T;n&KSNxARJrolWg)vTduh7} z3>G`oe#UTx)WkMUcpKX-ZRfX;6l>^r70?Pzn(&P+keWLYc0?fZV0yHmBBKor3dt@# zF{FC8OK7E#FWr4gJ^Kf_D)!akmv|x|^Qzu9g(PwikxkVfX6wH_1@TeX`IfTyZh$@b zOEA^+`lQ+c_LPHOKl1!Z2wWqinpXFUU6(U)ti8#;d5KQR0l674t zFB29>ELq6NHT?SY(Gt5dwnm=V>9*mhAwMbopy~?$`Ma`mqJ$3Kl{Enx&X;(MDe#(O z>rvJ?5KdU_)x&k~-WBMbb*t{GANg2YAqwkko)vX**}X)xB>JaR zR}qD$#oE1i1y1}u0Qw4ecW`(H?1F@xE({k|QwI8wy)l`RymYCJd5%R<$42z*j4T}~ za_yEl8`TwZ)aw@`4-c=s#}*)zPUjwYsHlbg-M<4;OmZOrsr4skyTg&!TxDzMW6ne0 z4EwQqt#+;0sF9q*T3(M5vTU+OcGKXbPXPOZLb}U1CI(bibko6D1MKzy8>-_+cE`Dk zavBE<%_<2Cb92u{S2rs$(O3vN$6~%VMMl}LHYS0S5drd|KVq8RL;+nk-q+~1?#-(r zAlxkzI|8E3r9WW$+5J9N#D0~2w($gw>{8$bU4hoC?xv1~Pd95s5qT8snT&Y>or|7# z^O&0|R%M6a-vP+$HyB1JEPNOCDnvru?8@2W=g6BoW0uH?B5oZ21=#2*UZsaXP(kZf z(gw(>3la74R)3<7+xtaI0Ie?P2fHBbkrk9e+4 zaz%6}G!c_Q?|^>XIQ8)I_qRh&1$Ni6J0!4{y>^W-Qs{hCa&q5yuyzdm*80-gPw92k zeJXClgfzH!JSfSzgY)C>`EI-V@If^=5Ub;wo;lc+C;o=>i3$pS7d_&$)pPpN<;!a* z%?7%o797zV_E)Y%gHR@#w&DpEp~g7VgS-t%C5* z&Qo=^ec_T{)_WrEBEQ=yn&GOEg7%xWzk^JwWNP$8yq7)|a&dK-POT?@L3UvkY5JD8WB?=We) z*xu6IOsb8yu33fuxiPW_$e`y3A-G*fxuHQ3*TQ zC4h`e3~6g*leTh9aW3Pps~Df1=f4P*$yJ32Ku+{gFUSY>icqv5cr^ode`H@xV@pbo zK5IC!Q|`ZO^Gwpp?5);;M6mTWSoV0jxwQf*ho>A?V~*`}+nU3MMp?O4kCf$~H+J7( znBkRij9Rq*X=oufYj;+jK>C z7WHt%i~;Z3`RL89Hf#IHw{LZ;W8%*)FFUOKSx0T~Rt#CF*Kdz*J9?%WRrtn+@^W7A z_MXs~Pc>SZQdLzgfpy(Hz!n}+YNK;oYeR`3KgQMS-j{<0ask$@8;klg)<4||UI5D4 zyB0#`(>3xj%Ud0b4GQvIoLb>Z=dG1F(8Ct?jQX1c$#sxm1#NY_4L)JjEUmiYU$<%y zN&Q#ax|PM|=c7B(mLnIgp1H;$Vk&B3(L4lKlI`7ossF!jW#4+ZYMI4tP*9Y22pX+);#7D zai#GHSUyE;q4QMz-~j04A%Ix80}>6`;OmL@o(@U9D`hAY%XzM4h4KFWb2jLd7?zyQ zcQQ)5jVYdnV+_~|e(b&qOe*#;OhmoZW6TU5b?3LHhNi?$$Jo@?@EqEmr}7SRWKSU&r+f6dO!;aJXz zFiZ&Ne377wi{^n8p?FupF3Vp!i4tR*z5Y>AdiH#Tg@qayf@5}pUYg~?fRA)^h1o-o z7R#v``t@5mj9LIad*3rpan=3(%KDT7Uui~0=aCQYYtdSb^_7^xLG#iTpGDapXn=j2 zPdkdIUT6rsa19#VJ#75N9eZ}Mf_Yqt(_=sq6<`mj&8*EeFlAKXm(ac^-OpmKs_d1t zX(Qv-)^smjs()589i6fw;jnNx`G$(?!?@0b#Agh8nSZf9Y`gRK9}bd`lZXR23-sP^9%^@_al4Xy?sj>Nb9CP z(g3Kyp|Z-#j?@uB2{=g@1X`VIZ`k{0*0N8LAMrpNY&c%H2Ms12OG}j2SxMqqgV_(S zC(e?dBs)y>_gi;hG$k!&X8bJLzg!=7krfmytjZTXKZ3#hMHM8~l>9_8;)V=2c%;N+ zEPN^yvn$U@x*`hHk?y|~S^g-IVU7g1)Oz6_2}LF>^7dn}|5=f)f&A)Q6Df?m97dQw z-+;`MkS67wH(FyfBl>P?{lK>gHI8)slvVhu&yIuwY+Z=Bke|7OdPVd3(hnNfC0%gE ziN;uU=nqNA@VpQcsdIp++x6M_yLRt9g&8woU1vp$W}Zpi_1{accK3PLl4lh<{59*2%QcmcCoDM*&*20a z{O@;VtU5*P0$`9gzDtE|JBMF?fraPzT5cY?&S#)PJ6b*d^pK{erj%3Cg4X+USpA30 zK6)ksXHK6s0TPTXe05tj-5uT=i$zZ8*GhWz3ws%eY?R62e^- z|8k`u1-d(OtKSEy&IqrAfC`zQEBXKt^2$L`PHs@hYkcH7YytVM%~qgZ?9Z3+l_qZ| zI(IgicUv;DvWZc9g=?zXY^zGRT*7KZPfw5khVuH>rmd~*^*dPMM@8vqS%4xd$Ig`p zJ4}$r305H634GRTN%g!2^4;cQGDouL4pBnk`+v=-3{dz(- z?(CCJl63>uhz9(bBvHPosHn>TF&72egub!fR!@2mGXbdO=nir@NbKS(I?*8zzqxvC zv%B{nj7g)P_rNvvuVHX^S-RR)JeCsRj-D(sG(0dmMrJ|rGkwh$w34pohAg1JKYm>3 zd16y&|Lj))P&@yq{;RO|(aRUYAeGrp=XDTgD72!O>}S#jyM;IGq$dl7F6!Tpd53Yp zDi42cI=kcnVyI7tRt>*F&BU+YxY4#eV#0a1XHAMi5kl;(b%<&9?7aerGJ{!knoUa| z>8`>@N>e5SgKBT@=fnJj4d6SxPLO7*^;=J{=^IFrZe1O6bA+YZj1)btGdM;&|PX&Fo+s2yHwMv#9tPi8;WxIZNs@>H8tOYs>Rn#+~4BD|veQ97V6e#CT(6 zO#Pk8{rmS@Ss=cX^+1DNC-E@;HYlPsjKl`Hy0`!mk!f+@HeuXH2T&gzHfu~H5C}(( zfP&JENl6KbPWJ~;_-LEiHKuPU5-^cRu8!oP{4p7t5nbOkIRLAp~ zyFs8u&CEEV{6luY_JbpHps*@qXSSM&Cg|*~t0gM=R8ZQ;U<>4Fl8AeB0*@U_Uv=n4 z%s9aoM@EQ1Fuh&O?~mAuBal*A0}Xj$1?Iju?N8)d4kETh2GA3WK#8n(eB7F&u zCb1$7&}x1I7kij-L2?>XFmfKc*T}disTrZ9uG^qxi)DB3Yu z?hL(s_YO=BAvk|YLBWH|Liy*qEWh~3jA4_0^T;8QNZApqS?=>A->nZFavHX{chAB; zZYP+fJm(?&C2nSA82}OWrr>```KEqXvF_y3Bi9dEFVrZKo~fBJK7Ccsyf-p3;?M&h zt>P+$I#y%(+?)+HTjYiqTnB3e}q0rBUQNr9aQ<(D*;-4o%&cEBR6dA^wU zAm6?RhWR|?5jd!$O#B81AsKHDVn@$q&#&M<;Pb@u=@452X#Bwvy#$%Aluw1mRAvvx+QQ9sJ6dZ4?;gJ;iHILJy-GpB6#WTeq<&}XR zvkoE}#v}f%W!cjS=&7rSdv1Z4)>aK(drG#UG}peM%M0D%8k^Bu!*SxoAhbd>cR^}Q z`%dzpgE#N;NA7hpVY%|%bp2X8TUX=}pe7Lsdi;)ZHzOO+X(~4DD_I&3F{gTA+mx&m zD2&#OPR)TVEo`IjI1rcVPiqiMJ0)jce`}I#w9iCzmPTm^K&6rNs(@-d&NS##XZf2C zsEgS#{OHy&{MDRx=!?RXa@Yha-3|^Po8lT4Jv=fzY`ZX4c{T2j63YN=txy54y|)M`JgfPBp9u&iXlHO zbOzM?9EHr%mUhII_Grr~qg__-2&Pqa-5+WRz>H^!eUE8NA7nlRqs`rU>P=HKJup%j zS|=LCy>H)v_FLCg?+5su^H%`URaB=H;PUi?L=vPNBEm*<5sF7KT~lA1rfr~o^k+>4 zT3Zgo`4;=%A0}xFEK!fD|9Y<{fEhxrCHhcx?f!c8J-2`;#)YFEGy%6qxefwDseR~F zqWR*F&Yc77kW}a(bpc(9HPRdC;g8rWIwC-7^z=`fD|{b)xEZkdl-c}4qmjP`e;5D(ZRN>y zk*EKSb&z0P?7r=##*_O;B2@(tTL=ti)c)Ngfw!=8GE;?mCW!Kfen)|12+Q?Xv=Xp? zy@d}ubpbS@?|YFaNoD>}XH;S9|t<`RHGNboAitDwOpAt!o^o=e!2HFn32_QT2Zw`F|hgaVEy~H|9C) zG;VX8o}P64EsWOnuhS9Ibr>a6|0k>b$F&6+lg@|Q=;uEu-^C||LAM~{sf!-jRLr>l z=$2$4sxZIhBhGw}P>How-rH}>yr(t!RqrvIs5;bt-xCdL!w>wxG+a?&T^etmjGU3+ z;vH=W2-w~Ax6r5d>qgdtzM>qmTLr$^!hvNB>#-rs`CUxPX)qeix|Xa%<2euR-#>Rqz?RnJ z(FK#|)00_RW}pXVpnq*hYx3L&X2?q*(s<7F0H|Ji2nUUC1E8rl1=4l!63Nux-~Q{2 zKaRsHtKNuTrZu|LVDM@S3tBWD{R|lV{!j@T=Ht?ZLRGQ~$7u{t;LPOd;$vJ^G?xDJ zSm@GF5wQLz_I3UFr0X<>(0))()eNI2OZ_SdDbS@{-_PT8@~SG;{wFwTOyx=ef%Jx# zW?wvMtnju2Ro}a&{ak4My&z?c`8iqZtvWvIE0o>(l;(3_4n4mWO2hER#|LNDes(^B zOWuJ(T)1hifeiZM6jP{KjDaMLr%P)5v~Tym1MUa>a{9y@FLfF=g6;qIYwJ^ccy`eUZi&W6#*t(oP7EJgu+}GF=d5)RR-v|EPx}kl&@S1the*=5? BQiT8j literal 0 HcmV?d00001 diff --git a/docs/images/providers/vercel-launch-scan.png b/docs/images/providers/vercel-launch-scan.png new file mode 100644 index 0000000000000000000000000000000000000000..4e7dd36a25fa80b0f3865539569411b5d260a1c3 GIT binary patch literal 82946 zcmeEu^;8o)M%Szqy zd_O(?GWBfGHa3{RCgZZEQ&6Z zLDYd<+pNpOU&bWlq=-NL_5+BV#gl$?D%MPu5sILX7_}$HK=nv{IC^~xBxFpoycdV1 zYUQ*wRuiSlrIbYdA^wp~HuQZ-m!{!eREmNpr4&pzGNm>KwPAl?1y?AV`x+N4kK--S zA37H+UHhfQV5Wra(;3YDfi9CL^v(m?McIKY!H-?SbX}U^$u`CV%chdFiwBaE%C%W-Pl>Qyb5jCCGuZsO9pqZnu&&_sjMsnE%+P`0y4+~0vdb< z3I5=MKj4vw4TN|N{ze0TM887)C-qhI*H`~JhoboP;0I+9NlEaxvXO&{iH)PVtrG+t z@;mUWrY%%7oHS%*c#LeV84ZkW4NVx`tnGeff#7rF0iRl%I2jPTSzFmS^0@Jn{_zA4 z`25#xCQ{-*9&rNjlWNE+5R2G4m=JR?zGr+-Du6&tOw8wCY|5h~`th&q;46Mob0;S| z9wsJNS64UcEKDpc4B#gi9Nlf44BQxO9LfHC$$#D>YT{_*U}5KE zVQWMD>%9hsw$4ucq@=$J`oF(F>uKU<@!yhc9RF$-xPeT+Qka+--!uK+yTMuce%<9! zuy8Z6(iF9@26qp*3;}jFZoWUB|5wU?OZ;0-jsNE4W@h<&&cCJnGpDMfiGzr(HMmG8 zf&Y%oUzz`&_*X_gre7`pTTlGi&41hl_p<;3AJhMhnE*mE2^M(lg&-tFKd87t9%jI} zVMw9}(vg$Eqb{Pjy6)Ho{a9LB+7jeiTv}Q?T|GWNwh3w$IXu~yWvWg~n2Y{&mukk! z$`3k`>+{i`nv#p*<9~vOhZchP=W&P%XS5?=;|~G%`5(t;atO$f*O33rAS8qh2`8bO ztN{0~6bLA^(SN)IeEFFX3N^av{WsKql>h-vo(YKx@y|mSnwZ$xK$zs;DR2^euZSU_ z{&6(H2?_0Y1_=M-Huw@X+70&KO?G%F{V4_krG!n10rk&@p??0{#rm)66MqeZfX-!k2`SE6*Zo^?g}3RP0__SV(&mZ6t~z4Y^^=E+{xm z?KPlrcXLySr&bIfg%hM>WMsU&yD*dPZuivN$d@g0N@?G{Ju})gGC{Uf@YpUHScm(q z((Pz|Cx(79NsI&pTwYzbQduPaBH^hVwu}dIS=@s*t)+8Scn=0K-9-i)Jt~b-nET5m zNlW)6x?gRc?t9LTW*gHc-(6iFY;KAk@i;|WTg_J`B+_fkJ)jU~^FN>{BowRC$RwBB z7Bx3FSC-49upS(d&JN0^@W@8yn3PPbEtF}2n(RyWHMxEE*^XvggFZ$Qiol~&)@X6& z+IB?}q&3~_N?zfyeT9NSm_3pk^*ZAC@>~6hPtnor?g)+UORTu#Yz7j_g?2_V+4~Xu z!@3c%mAZo8T0Aw?lFUVv)z#9Iehig>LBPsBTBzGE9t7TB9*Nf;OvY?IJw5HUzdV!G zvGjzX2f?Bce6$$P&wKWM7_o@ z+8rZHWpPLA4#iAEK3sWOdJqr#O{`C=QEx5F5Wc;w>@L03_wAqF8BL>$G8u>`F*Dmi z-DkF|#%4?}r~_$_B@U;(T6v7*4hd+c(KeckxLD~9Ga20)NSfjQ5}Cn^*S(QEmP73t zd8pDLd=YO zZ&6cB!{xA)d12K3NF|p=V%ophMv)=t8o521L6_E-$luJ@)Yypguw(X_q5QGM>3Dv4 zHlg*-WGKFW_G4_WWW?1ix#eVG4PaEy{bkhaPGW&*W`a_DJB`oXVgJh2R;%5DwbGN( zkyfiTxsF?D=mF`S1Yb~sUdi706rc+r8uObTTNOvQgWrRsP8v26kCN*6(aYz4fu_A2 zzp7}o`Y5TKj|+;kIksW*StsZ5xD2K>Ti+H5*V!Y3qmGjOH`yf zq{Y3765L&WdZ3kV@a~Cs2g@-!U;!5)1~qY3YoIJPg~jZf)>O&(-NlZH`!QhT@s85F z)@CAcykL}gVO7}Aq@V-_A8^WYYP>LY1(t`A&+biWR%15(+irdU|fe?3+DDSCxwQ zgD{~Y-5u7OXlt!!GUw}TnV7u2yr{)T(uGACbJffBOGrQPw0T`AO&f64cDQttMC3(D8xOuWVIa(ft$$73^iGxy$z zxhR(GLN=P1WLUpO1J>=H9O^?Wdg2gRkM(0~$K4@9%7wb`vsnbUFRrdCvRH88v7Dm+ zwl1~_`k~eeod-R|=1KKy9xYXi6S^KP(nKAa_J7b*Szl$^pp=PUKilk&Q+dCV70<5x z5tqZbq9S}tsXM&4?de|n!;MyO9Bl%vQvRhyk>1gKJh!x(5e`2U5-vxsjV_O3kCR1_ zY8X}*(eV<{PPH>>VRvSwraXLayzk1*N_Q&F&6-qPcB_kCqoL@^$zxH26-J{?WAd~~ zTzczwliDhs^Yr+ z*cTYcBh!K(K`4lH#w_A#tcg4JSSWV=CIE6oW$S@-3dCBQIi(RlvE=2uGp#{(J-wr!P`33`jRp#SeuY%E3nr<@3kwk9vt^R~K9@t>(x^yb3c!}#GpVNm{vl|;) z)oiY<{uFRCf6fj&NBT1v(e0cGr6k>vfuV(kJL~kw8RORQG)NQ zn~B4^Dh!##F@r?`?$TuR8tJp3i}_jrCEp1AU>rx~tl_tg5SR>(%7lR!r;Babxb-AP zoURP5q&~*T;&N6~@06&)T#{j!W}U=x1;uThW|su6WaR1w_lv-x4d=9hR#oNU&CC4+ zy7N>9)p-z)48mT60^nAo%ksw9c<>-$Fv$e5I6QJYTx>j-y~Q_)NteYU>E==8f(@(A zk;U#5bzOajQ8$-(b3Nx{WNvpD7Hn}*Lm{5!p~trCMGw-(MNVm?6^>aO{?XNBQC#ty zkT_VQk{Er|%mR{@`z|&a6`bWwJ5$P8#4HcYww3;pCper0)|(?*@ni%VIIDU!+tE%M7%kyr}eoW<{D+ zu}Tq8^(Ob5-aNx9|JgN%#!QWgm*}LXc&ygO z-QERN<zvO))4rOG?E#QW zhh3RjX*Riae7d{1yv%K|-;lyqQxy;kjo()xJXva%K3Q&!8mwbe3?0^fwJ`Uk#qru zsDZ2a6}q*=)2TdEz|$xkpp-W6a6M1J{(Xa+nvSJ zkGicM3Fo1oNvdnXTb58tw#nTCWOLE2Gy?PSd&2 zD8+X+yUIYasT^@T9d{dD@IN#(8_w>zBD+!qeIXmSzO?#i2+`d10TH*AGg8?j@RKF; zFZaR$(3ptQ*5~QsQMfd=_Mft!U%f_q?O*_D28Yio7b=b=D4p~OD1uLMUGIW-H^$bA zY$;aC@VGKIRzBX@loUykh78v{t==_`88}eEwys75#F^@6$@@f_ zj%14D^n@pz<)R4mCC{3Efe?ygtO3)%#rN829 zOo&+KFCIDIO>7nh;+dT1v*z`OeG`2^p;>{?`D6N2ej+{#m$P7z6Pm# z7!bygF0i^&i^p*UU+Jxh^;Oc%s22u>6ozJi|5Y-T9$ACg4P%OKosK&V-0)x_pl&jf zfK^LRtz0o~x>Q?!heL7Y(Quiqk}&}EO|hX!%i#45fI&GQ zs6kx=m7wBwJu2WS(s#9b*7M2PJf`PGB1^0+I-;$@4dP~(!QCQBrFCUAxEHFUA)KD zu3U-erqZ$&@D+@Eus7X8t;N$)cg*r#5%;MJ4wGI>bQ1k;z13W{%^V*O%Zj(>jTF}7 zn~G+7?X)?=k?GN5LprX4^<1~VT>2vFZ2-!^?Iui?@w0R>z#OK z&u4+kcr|%aQ^jm`R|ys!-QDt_s+MZyF9VZQw4t)NifcFy96&J^n85se*5+BRx<=t zhv;g7?kgOb3lY}e?A1Tejt)@>D3)ZQY@FY^?Em+||K;fr{Z5fQU%4Q&KUqYhe#{q7 zYyhQseVozkbo=u|lha=8QWN#R;iS_IcrG!pt&Y-f0NxINX}a2#1nb_f4>um%&wv0iSJZ6;p1J=A|k+5;}2 z@bgdx6^d*YciKo6uQYmZRKcs)*Jrn*3B;QjNY)8)46X6c-($&wt>O|;L&5n z8|?f-`MhqU_1Zl!sb9zl)MvNJUB&rqizAnr%1)z8~?>Ed>+em-()+axqV31!pAsK80fuLWV?Sd40 zi8>-Vp*#I+;MYx0oxni{f>w*!;F!%?Qw9d@%7IO=;iA|o`&i+y_9Li3@8uy40gE;l z@CFHwJzwzoRzzJB1Azz9ab#Gl?kjkye%;!ET8P7-#g@wM%19vS9!e>fDFc`W6-1=f zD@3MqN3=evUNhlx8f2gGkjstdN{W=sl-19(z4(-AwFV|K>VKeXRhuZP-Z5Wme^DCJ zs4Shno5u6-DL;&O(C+^J*pr(-oQmkZXS0IbokPuxW6L#XWW<06Mz^CK0h14{5M@kc!Brv!kDGNN`DKL}I8XMBA zZU-si)e=0lR*k7tERR3nr$hBRAVRx<_{ z91>yZ{fT-e0zR*R5xoY9>g^$lXN3Z#*$RWLr`FfV<7-B}At1)Za;aJ%#9WPYT20%K zeoZnOgNM&Pg90jP)g?8W6 zTP?^X(5f>x+WHuj^E? z)A$nI@o$+4sL?BPFlg5&wlA2C=%XHA@0kehzkc!UZYRobB2?>o8s(hXaZam~G+ zHdkeqGDOjuQWJ#6*uR9S9eMi+JxvL)h z{JJnACEyD~fkb8dv*3O0*RARR97N?SzciDj^UlzHEJnkxU-})B3W}dN71G2|3I_xM zG?I0(lqL;wm5CcgdzWF89v$AaO9qtgqT!T-6$z0$#kJ!UgLg?oVQ8Ew^vZP$!kSd# zc_W7SQH9sR{22TOT2iSw;Z|`wy4go62pf-Awpk2`#qvJoDJE&a7sX+c1sbWv&8qe< z5rI;JB>FY!p3f7iP786P{Gqd?hZ%<+gHwP){(*5E!b=_jv`2n`R0?_HAxAc;cyiuBv3#_dIva@};i7RagcAu!|Kz z#X4p^UxX;?lDE+hHk+LGB|xd11)IW7&WDSd%OejvS(ok0-sYVR_A0HGm>!S2BoWv| za;odkON)z}d9^Nje7iXBb-5wQf<^a)n2ZpnGZBlRWH8L@n9kU8U%X33xpIP;wGEV<8p}$xQ zy|gLGobsvckAu?ECuYZTip1;7V%7b=z{s|#D45)tpLkCuZe3g&f=q6iBN!mQp5F=CEu)GUDZQ z?Z>73$udjS3yMaIogd%K#l|wXNc()1*4gdjGDVZCPnMI#RAQye^X0X>hsOg;-WY-e z$>HqQS$mlH?(jsj(qsI=GZV#tj!Hvc5_JhW3~sF4Xzkm+8ec`hu@yX$(zfR|hXn9iC-rvw;*RVHT}@MN%afit zlv3}NmYfdNsIK3Lb((lkB67Z{W~eeS6L#$I5G|2ZG(ygxOOYZoYY1_Jw3?4ENAXKI zFqon4^)mtSHkN;A?K|Tig2zyZ9dyKrp zAhZ9dXcklId$nrm@pRk9x58P@xg=1VptIDexaF&+tU^NSI_CJM*|No@V8GbysAWjsS5eC#L18cB_R~P;XArde`F3755Mew=JZkfZ*Y)_P zmcbRCpbLE^d%#3C45C$24A?a&A6jKL`UU{JeRU7^g5^r%Xn%<%mz5Ile$D@^Fj{2L z+I0SkG3$aqlBd~X1J(lgq(7R8<^Nn*l{mkKQtP5}vdz@YqZTAzi>__Jo78q2=;t})hdho{$u1!vC!>E|ayz@qu+SuQh0s$fP z8M<<%JOkb<&K!=^8_zk=%x4OCTe`|!_gL+vm@{Q2yuo3OWgoHBncpBi`|#X#w!uPI zrjevYBE)r?L}X>Zxnm2~66eo(VM*rYs0h=snKz2sNi!$IZ#!3Fx;h(G(>T^!k0~>| zBdYdOSPLu;t_hUfK)TgEHja-b(62rBFY0fXFh`#xNs=|v*-^7qFlAZw;X?e~s3((b#oRpV_xULGH1pn5$sfI(>nbyx1ek@%@h4 zy!Qh2-h>n*O5y9deILv?MlrnSO^fbZ?5)rVG?{hus(ubXs8ufIV%w#rqGBz+^VhmAX(f6&loV3w!BwV%j4%{oM3K~u zVCSXlms9%oz<%M9w+io`;&O^)eI+dDv{GWVq?1g8Qh^6)MGW>bX*q*0$pr_Q+l6!k&K z!Dl4Bkvb9;DKWP7nto}e-IwSJ?MncIfbDWi%&=v>L!;AK_Rz+6DJh}()VNk=Z4b&@ zX&4{wSg!RVDQuuNt2Q}ztZM6M(q3|5$ULL}l_Yk46KTZ0O(DuoT~uof4Pb`j;K z;-51}-BYsOF!FrhgrNCbwb+7E6{pQ{)XR#&%`w;;ij%gw0wR~}N)mz8f3wtL@$drw zEWCNP(W}xT3a`~>h4Vzw<0Lw%svnAjhef4cuJaA-HUnWM3U>hPHFe?wQx3uOkvT-Jiof;EQ<=ups%)KRNlk-*nzecWz51< zTmfASR~A)<)8@5?$BdqboybeIUh6_z*)Yevg!%~7r3OCdumLRm$#O%5hVZT}>(`Re>aX+~IxZxGKFn#N)!7nn zB{4*du^nHsoM?r`K@sYB3DH0L;_6w(w!7tr$Gb)EqsmLfV8RD3p~4F;LLGi7&Gb~o zTk6U@lbP{ZJ;eGgj80un%5q)IL>(99DZCIh6uPN`oDHQbJLo?Ey<2CvfMCRu`{)dQ zPvj+X6-`xjc`=vabPngxGj`i!d`$+OTf0kUAsNesJMsXK!@|V2HZKvoDZOkeOM+o< zi0qCiMt_lMS$(t1aqhYp!o*y)S&>5mZH;tk{U%CHdS)<6JP={Cz(hI`ZY?EZ8vY<^ zdP#Ai0OV4$HOY-QkCeutO!+o=2aHLvxeVqk0`CTc?3DEzT=pZX=Zy` zSO~Y@cEB4qK`Q$GA|U3t(t0g0@%ZdwWO1ne=k4uToE-?stcWJ1_as8<5Es<;PSJgP zhF0HmvCVsK_nwA?;1!lbNa%+oPN=**q zVMN-JBzNmu$d*aRkzPr3s-F>fuz+^U!ReTliz&l5`>yRWb5)zQ4tZ0wwW6DQKI?-i z@0bk-oNKHs%*Jrh_PTx51M*5z75QLmQLsL{jvk>OTtCOkk`Jqe+GH#WXD#C_%hyhy zO*CVZj-GnBZBY~G^M?qud7B=pJv^-85+~1kPbw+h2(~`WQ`Qe#3p84s)>Np-Z#5!t zs$-eW=VHnj=;-uows^I@YjacC@@n%U$6h<{&kot?ZjQT!bu%ku;fP9IAu!_Bqc3LN zGufk}&+joV@OFW>;acN5yO-cJSZejOsrPybzdB0aHONb~GuA0aj{Hk0V)>y~3RN}Z z`Sz74fpCwOntKD_d_TM09G4)bHT9b`%Gn);x#>X{m`^oDguukl^i>Y7xvwDpp0l-S0f0om*e0*K;%-jb$q1)fLS%erx$m zGOxy4B~neq4w%V5>*RMH$dx=t_C?+1cH95qg%PTKFhZ^ z>UkG-8f0&>#%>CmzH1TXpJI;Q94UZaRzzRpPd0~Foo7a>wAmLgq!Be5!UWOAuG{FK z+0?l`kg>4aIq<+tDV>>qeK==b=`Ow^?oy4hlze27uzTr_`QOUFVoE>-);M#Vo5eD6FQvdw+%Z zG0D=pt=5s>XshXvMXN+k_w1#Qm&fOk`iV-Xn}Nb}WBYj)p~Yh2;~s6ziw56J`QcT&}l_B*HXA)m;f7<(gMW}}4- znz=HC!c}vtCi0zMq0iN4+4b_1fWBIVc-d_Qw-E7v(8Af>+3!#l#&3^yXGY7*Yc_N3 zzbN$0jqd&WT+yq9SJA6SB)3Wa!bpw*;J@QfTi~cqzJSqWP%DtZD)xO^m+(|Zp|f^R z|C4n3xC|}a1=ZijrGeZGtb9M2Pe}R`uAE_#lJUnc$;)Lm97b!7x5rS!ip1x3KK*HM z{;FnqcuEkCQ&5j8nI*47HI$6C&U!@-SzgoZ88gw}_x>sgfXBTHCys0Kp}$D`hVb%a z+~oWRx$pN;Vu8=q5EErDu`t~z+DCRcE*FEuP;C`qFm$19V{LeXJ`}_*>0Jt-``1F zbKeWtELCZWYU@(GnpY{(QiT;8h-If6#^|u0B{jD|#2eXRck#ZzjyrJRwxk!=*;+xY z^KvwV90mm5xkmdpoO)+QNok9=(}!D5m62s(A6MHfdF;DX5L|^P@Gi7i#OWAmfV7;~ z*<+?-TkWe=6PG0J_%|SwA3cZ1RJak|m#aFFgVjUONG7*PtJo@oPuA@Vigb~}T4&A4 zDv1;oG{0|uSJ@PPO6n`Mlmbsf0+x1^$7Uj(v7+GzyUqJz4XT}|xikb0{Eu0JUKoHS z4&0Ipj{$X*6UDvAY9R5DnBqoWe1`>>Ls3;B4&v){ujkXiGD01?oB)S_nO*qt;IF*s zMGA2Sof#9#O@?~BHJMx*Z^Y@h*xh}n_vlE&^w1Ar+7UinxPUnpl}`aB;%;vtodYpK zQU+_j#=Fy%ES$T!9N@pbEr8f6IuoQpxR^SknkL@PtzOt3c)00q(GzHq?(S+pGo>Yc zU|6!p+5$~!H~4xCeqtRW1~ z*$tPsWm$1mLf1zV+CCKmBy}8IPL~ajr%NYU0#!ppI1_ovo2ZX1vJzLR>_x3`vj+WF zqiVd1v&J2PWMYJT4k|u<1pJn{7@u1}5Wcfp5cn-o`Fe=tS_lIVv+AOl+YG$8 zVYNxT-4AsNR+wi>&_b39^^sn%^jBA|<(VuHaWkp44%&&GVxa@O&9upr1DJHVQ|X|z z10disZN^q++QtEu61j6CTa|7dMAZ|SB?Kn=#7~n*KY2@MwpKbUSh+7U)@`qSRiu3% zohNV=p60K;gnE$2{T<6T=}9YlNq(M>3Zb})iTb)K$D;bp;W9%Tm*z*h7PW~+ zuYrJM@ux zfLP`9sdapj3M)^=?B(Df*l8682lA&83F$E`iS~}q|HLrQS`ft?{U&TN!Fv#%ZXd6B zu~*uvqf+E@O@4(u|6MhX#--RM0L!h2nO4BCwBf9GBg)3$8JeIaqhL zwCC9Hk)e&O!@UNnDj~|hx1v@8kT8~LP=ch*I%{Z=IlKNtjS~~D=dtY?yg$&1Tv$gL zrL8nc0Oqg*f@sYS`n*~2q!Sg(dKq2l39qif(0`p*E81I1&96Z!Rh*_ily1W*Raj|J zKhmr3ya6*-6zfdblZ&&RU8GSr7CJRQo9GM_z)OD&n2H)vDG1n5y5kdAP7LsW(2%lP z+pYx6xThv<@Z;YhB3@C1-aV~0)p4qcKU8wsJo85p^274GpL2EX^ca~<<4=a>h%T&y z2F`D9ZxrMQl&cG-3|qQ`$i~z`9L5{4wm571gpmR*&rR23AMM@4>dWAWxD(&F<>(@U z_A7;qW>j&)dq+G3ReRkq5>4uwyxp$4l1=u=bvBbZ1}ju2DN56(+|Q;-wG^$3P{c33 zbSf>pp1HZWVul?wz&5C3EdKg&zG^@H#MiXm2rvDpQptMlPZs{ECmNhRWdAIeFokwA z0tP+#D}6gcaq7itPizJZZ3`WAELw8Z+bMXv?-W>S8@-Wl0TSMYN_hj5Du*aq+2(J9 za$2AF>EHYO%}wvO68GKpZM2q?B|{WDAhV8sGy+ekKk5h$IT&{8HDpXGO{2P z&bj#w^;DD|g#Y@B!JEr%=(gt1Y(x-cAO011;)4W5f+e~$lPvHN{TP6Q6g?>tdqb`_e;$Qu7_1~xrKLt53lOSFYB3a-!vLjfG zcPYSu9Z47i{|xL9qNaj?#2FxhkoleP1%~x5(ZI1I(g<6>apk~mBaTP^{Q1om3Pe82 zKO5r#CQa;903H6^YybB@>Hs()@ccEz#6QUykgebdn5$S}?tiusZVQ|sa`)=<-aq4Y zKI?&lT|6Ye;s3LZ0S@4VZ;z1QFaJ3NLQLQ|p4MCi|v#oBQ}IcCFqti_uq`O&h{}HBoAR>MSwpmI$L?jL75;hH4#|moc&nU2eaEXFXbi@`d^5aIf}%n`mdf!0 z>ceNcpPCp1rH;|-eUsXL{z*CcUM~H;S>et7Pm0F$&kLzRopD=M{i_mkUqXR-p_0q3{l_Q+>sZ+A&YSxDa3GjadhzT zZ|7`+%qIS09KJJ&tv16;yuck_eh3!NS`4&xZKtAWhaT(aw2*P&ck)kfTaCKEF^+2c z)!bEe;?qiJrE_VF$W9wy;bT@?UOwZb3)?=yM7%r7Frnv|AEAA#qXafTTE0|Qvx1|^ zQr5ddM8G8OJSP1&fcL|LPnI)dIpPH)y3OM`K`4877q&YXXczMFT+H2}1ZkOq=*NR{ za+5`l*a$=_oF+;i}oqo#UIhqZm$ z2U!~%8#b#h2_A5yAA@eCa2qndfUxyKZIU5n;n8!U2RP8JfO0q$r+GA%9d8Pxo)wyO z>;6I+1tw&vd4Lj)BGD)i*a2f-_SwxprTgDWPVG-w9NiRBxXTLSEG2 zH*%cR8*U9a;A7INI^^QS!~EJ_1i^VFc@qn=56CYAfq)ecA{oeiZca+S-Q+(~)d22WD)Z9bi5) zlCin7BmK*bR(G@zC(ea}E8t`v-Fr($JN?#>Svg;Z&GFu8?rEAKtw>`{*y-i@iHI3L z=)vo39R_pghN{&E-AmEs0-IW57)Z_UxXs3okvO|5C9n+3MCbgb%w-Jum*|+o2QDQ%D!j;BX9-@W_jVcy|0h(Hay5=57JAKN6Uay`utzp_faJdW^wY_2poBvu%@1L= z|CUwXhla3K4V2B8!80CsbznZx6ERsTX|yMx3DQDxaCJ=riH72*+@s)&^17US%kaD& z|K8yr0y3c;PT|Z_1L=uqRvG8PguUdE^~y^O=9iR|(4z@>xfu>_uXx}8itx1fvCUB9 zc_M%gAi@3>Ng9#G6%q+%^DMX=$0oA6l&ebeMjBDck2S!fMqGP;rQyP9>fX4dZ_)-PUb1vU8 z!}(TQK{3>_!pzLf$pTyb`RW&lj8?mtM0))XV8#q5O*v!3OTw3puN@*PSeOiI;fWv} zv0nMi{0@;IMKB#I;^wwX?SbF(Nj_AZv0kBt2~6YIQBILcx(nN8(h;Q^O;5l_z+^17 z>Cb8P@%DNJor{uqko@@v4BTg-ieLNnyGp>`C!C6lz2>g+RS5?fNZ;fyIs7${f9xYq z5717fKg|aIxVz_Vj{9_W>tn8^IkL5QAheZHjx(=d4NLopicI9ANOa?rUWtsvbz^YwRv(P zj|l`AHDALTbORm?yMjp;86B1U10#09?k@~o9oK_p|MRU;riUnOL4o09{vZ|v#PxF% z>AmA6-d|KV%jK%P7F&Txkaiv1%p@9{*|V2nOrv8j@&?~DeAs?%$xN`WQ{&3%+8dj; zvkj`RnvUC228~7w9QX9oZ>wr+XI6X%n>>0f4n@=PxxIpCW3|7nt8>a_zSeeT(r+T4 zj%&;L07g}gc%1jXKR>Zq4`4_ozb6?^W=|s(f2RGenpXTG5rd@9mOC2lH`~n)marP{ z2M(ziQkbdIE7doS{MtuZ0^U;WvOA+0IU+&G0|#I#%J^>OMlj5QaEE+VhQJSMtEsd&1!>l zT<>M04WUC?{fgyF!=Iyu$^&;B#Q8{5gTb8u3I|UlrCY*4eqe%|lfGBfBGwWjbl)DR z<2+~njmmd9SnUTc-FBB@Q%Nj0&1#dJyNm5{a4Svbz&NBrT>fz3n;MI#|NIufr*Fc) z!qrl+X_Uxu**-yJfa6)Y-VaS5@lpq&D$RF&@Icra75~M2+-J8O|NOxpd^_Rc`Z&+y z3J>+QDUEU!v@W`lVaaN!s@`O&J7Ow}MJz_@_Qt9ZD-Nq^EUEo`e1BJGu&zcBG7f$7 z7Qnh#xjgeQrxrDDq0T18`*dFZ*mFDp{+GjFq^_sPI_lM&)m)2a!;@M}qAb=dy(KqD z*GOZA%Y9r_tI`Sw>`D;d4ti@?4<-k9LHV3yF0qWxM}Z?crR`@VHMr&ol7Lmea3JL3 zNYM3Mb~@#eiUrV^QalPjW@_GfR|0H!=knBA4nS~SY>&iXDVusf&N7crl%qv1Lzb0V z@^Ssz7J-@Y?;oe$j9|T*KX-NfHag|Vvsi@|xt%@6sSGujIDk^pwN=D>X^_6h>FdF> zRSDE}c&F{T>jz}{W#63gqMx2oIoPwb-0H;54)j4O!Hc(<$np(XE+SJ^ySz!c_7y-^ z6y&a?+n*?yzKJsiU=)Buz6W#GywWhDz2xB~h}H(&wl6I-x359kT?coD2nSglx=n71 zq2eRF_KyuMm}I6h?kYAJ)}jzZ3FCS4O!AsPHF0}OaadIpb$j0!wpf9kGk^m6(H*Ns zMoq4}bgCG`u7)_0B=8j^!S1t*|Snj+ya*zAMLeJD|r3 zD`{<>DR%29M2ZkEin(+K-pD)sPdF$*0Lp;Sm$Y4wuaDD*%c0E#_x7VEj^I=%Q^zbu zR5o;dN65k(DMR(ib4*%^!MUjtb=lNHg-X(HtZeJ$bZ!jB?@t$lJEJ`;`+Vs^25-Fl zyWcgJ6?Yl-@)bEdrkC^Y9N3YXqZFu@>-Cep+`66_ZZziEzq8%vgQwEr(A>4`z2^R; zSL|ye#mjNjm}e77$W34B9@VAQypzk+C`VoJXWCy~^Yy-Hyzg3~KYe zD}O&jY1(EnL3vfI!_(KAQDH?2$LUaDt54(eljluy=J>+C z#!(^Z2bd1p%nE;jQMAiLCoPl(552{CSIFh<8QGlG7ijqI=ZMkVDWwR1h6GFe?$D&K zmz`3LpE|r6uazQzzy!6SVlNwikge4mpJ&he@n}XmSR)71WigPxv|+X17H`1( zqs@2?4Z@TKhqcc8_Dp``O!w~uDHdD3TZ2itwam)fLm$Jer>*o~opOx}M1`Rv&Vq?a z(OIasPtSW~Ftj@t4?fZwk=%0!NrM%{0?y~TA@6p){s17yFbbErvNlNe#_vtechjvwaUDBSTR~8MXd$= z>ehuEwKtdP`VDq^Wtic3oMqvm0}me@;zzd(mq^6rx30p|uS3j>UP7$jYt>uRi7A19 zup&eZ)fT=I90$g)yGIL-8BEgg=W^dyp;c{SQ!P;x5q+&IEuF}alpWrCw%Yzu2qq3W z=#rOz!)G%N4zIY^gDzQfA`$vog;zQ~tc>(&Y9QfqYY-ck+p@;$#kch#*g3A-{6*jg zzACqP)UR+aZ-}HEaU=jz79yvCprEf5-E^AiNIK9hOKLeu$#$JRoIW5Z3ZG)e0vU%x zr)i=1-ebPqZkhNT5F$~7pO83lo+q8xKtRG}cR7We!P9Rh1cP2R!&Kkl$nAWc&Uem^ z_DiS&pnp+V1aRw>`29^?RpcUr1*dEjx^s$8b~RM_BTst(qAFZY3AR4r1iT#VR+GV8 z(SA9SAB)kw8yemTm+@)|HVin5Hq?-I@%S$6@8OIYR^w~Yw;^6}zyhW`Ll_*y znJtb61{>Bwi;+@Iwy(Z|mGbNSdup0R4wy}JrOL9n>};Vwz%y9s2ke!J${6@ZD3p`R zmW-p*dXRA84nF;S;2^rF%n>ijS@dN|59i|%vchwaZJ4gJoly&=CKUI-zuM%|IJJZL ze{_9iSR7l^Ef5G0f(7@%gFC@JxF)zuaCdiicZc8>+$FdKcXxMpxSb=fedqp}nP=wd z?&;op*RHCyY8Ad_^MKy-*}AWp#d(guooZ>98F9BocuMWBW+YQwnSLIp=M|t%bUT3v z7qURAB*A--BgXoA5Ut7PzUmI=fT%RuG+eP2C?uHtk?pIGs(>&vDW~k3NUM_5Y`l^h z>$`fk%DDnTS_vb~Y?`kVDPbWb^VrgB+ZS>C4zv4$d3qr#aHqfw)sXbY*!Hdit z5yIVj7kNOkesD!Rk=A(m(LRMaj;c>diRjWA;1SF?o-CNh46l;dc6a4&_)bLq^xY!x zjD=WTC-Q+=vRdCD1tdOb@?=tbb5au>FkN=63B=My1@dE#)O-p$1V!fqV0z(DLlqq_`?=X~H zHx$L-$Vm5gGH4@oXg1|Kdx7<;X4KR0-V#Y9Vw&v5=Q3}t-&Alow$9r)h}asrsnL7il*jsgPBaOtk&|}E2s}j z;!lB=2Uq*@vS$6iEQDOURdF2>H(EPPW{Zdg6O_unsGM-$Pz_6j$G0!HKk)umkc4&7a!fSwV`xYe(giJ5_V&+yb%Yxc(6!xftz z|0cy{!|9UyqnPIz7qg^zv;VveN#m>?90skxn}_S%{mBBXz;>N37u6ao z!my{MfpV|pY&)5XkB1H+= z3kVnpu3#bfN!NIe(eFj9vg!Qw#$0uz>^58R6JJH7J1LDR?%_-~cZ)s8cD-QAey5o% z-uzwQ>0t;#SoL;-u8Q!eo_Niv8R4>9H)>f;g}(Tk1eeKB(Zx*!KUPUAup3AuP<{@K zz$L9^XKv0rV`(n1;q&QvrOk#*q@A4D9@-z}eVtOQbs90HHT;$KxfzH@Q7QbJ_sYIUa^v%yy)_Sw)5Jl&*grfx5 z^?2ciat~8gDpntZ+tMTO==Y7SXjDpKO4|@na1$x^hkG~6t~M*hbUVzZH@F;*>qO3F zn#8jcKRAoUftWH90gp$3LGP`m(sY9u%00DJjeztL#^pFrKCYT;AfP;~x$V$V_Q+F;^M3mV z+CTP_-+syoq<|1#Oo>NV{s;GjCFyAgTxycWG@A2%%QzFk+M>f@TkX=O1tzNQ&?6Ni zf3!zoYa8T^zzX&YwfYn8AR3((dY)7ma2_?cvwBj$xiY(jD=hg2QDnel{$%Y1W*Y2I z6*@UrxjDAPUTqBc2D+DfNxG*c{u5G@s@x-^Q4F~)!>(c~5@zv|aUgI!6vD2uygl9O z1JBReJ|@$qV=9&PSkQ0QoJX{NbO;Gik{yYgWa##Ud}iows4W`hbuXHIeMvA?G#E}J zoPA4!F2EEKq2BbyJO5!qVZ8tvyjw+MCV79vka!wXte zU!FQiY7Mpd*7)CJV2wpPWdFCm35XeKtl|ncn{WmyNT#&Odd8ZURh2FK+26}Dg+37G|_fP5xV zDb<5gSS^SI8cyNmg;SBK6wP!UClQVpurPM%G;4yS(>SE4Y0Zzz;>AjBx4!#@*J+51 z^ualfB?*8fP^t(BA8$5w1t8>I<9rf}j^|X8cDbLZyrwmSHJfUvT+%94LhO3cSfYgk zW`N5e_rx8?$0FHmfeF>V#|-1IfR06>__ny+RS+R0*Xkzs;9OIK&Gx$i<#;-^I$Z09 zM`;a?Nh^lgu0VwG)@H{d-8^x!8TAO0RHDz~*zCG~3W>@hJA<41YpH{uAZzQf)gILu{!dwVKY-%DJ6$S--5xeC^+rVj7>g6@|<#xwNHj^UOO3Y@mx{bACp{wsXy0Io6 zMco?@fV#_6qn-$3q(=eTL$O=0B-TDJ;SVhpnAMTXP0?B|PxN0yi8OiAx|yu#;a!37 z#4AkIZvG*5+OHn-0Vb1Ad;RM3$4R%(s-V(eI}|`=k$A>YiPQFD!p=8M#6P@-Ke12X zRa+V)L>;Aba@ZoF_}t86a4 zKLixvj4SXG4S_)Yzwqo1gx`En4lQ@d6{xR^`wLd7%Tm)EqAMs98KN~ag$}%8BI?S3 z8FB^Ud5va=i6(d)qr0GJI~Ae17PtGDX`Sjq)9GTC{`>Aep>}Cyv2~(_~Qk~teBqAaep`r`MUFdQ|iV{REnMzqr0Zk?suuM|PGm+g1*xi)Xma}cq z=W#zPs9@E`JCA&_SfYQsxb8}gPA-{7ayw3asf4v}F_g0cXyKFtLP*(wjv$ca;_m64 zT&YXx`4gD=n?wM^_{XEjY~3C6s!0W*o0BvfZIan0i~#XPwxJ|8#*d*xU&&<#xe&g0rLrfYg8S9z4N=V; z1Ll4}IZ{Tsft|A%$PY?MT@1z3$pCN*({G)^&A!MXYi7&w&hI!5oHVjoVChJ=wZR&Z zt8MPY8X=)*bo{2>91^an+?AhuNU9~TAL%>~yh7yj-$=mk*aghnk`##u zT{O}5wtv6J^&%46i90h7yt*gKceBu_grIkt)nY)WsD(9>CQ_Ws1}8$9z&VU-#!?K8 zO0lW|V*`K(_IHL;S10VUnwB)lD}^na=E!uH{9vaF`QL=jbVDQJi^5@wP;Fmw)?1=L zhZ|4U;kA0+(#kd`FtWvvSCE@6)Fh({H9H>1oTO9Z1Ggzsq17JE??OGT;LN4CVrwoBR(#+(E4~rFrqXGLm(|fb5Ilh+u7>NL`R( znQC~G!yzryrpG$=pk6VZvO0z-s0*rL#N^Pgn_UfYwp5eG_f!Z&&GKlzI+d-;B)thh zAA144pk%utUF+J9tNBuD6fub=L^&y_Q|fGtv*9?O`pCrzSSl!mk1l-o_kLf^}bN|rvV;VpMJiRo9?D6LHJ zIfbpJn9LOGR|c2p4(nRMiJk<}sC*@pNpMA~g4=JX%$NH#t&KfXAu?(BE}NomV(seT z+Vo(&EESdOMqOC}XSti~%IvvRqkxvh)Z#}?C8^zZNIbL27EH66!4E34*xvBMuLUE_ zvO-e&Lxjx^RSg^NB(+5{r#xGXUVj*v`ofZu);A} z#6xO#XjH|AG-pRNwr)t~ZMVkI5i4yC<|+kUU8soC5@?hZo2nU80jaog-d0zMO0yMq z%Un4n7)gT;+M1gfVq1kx=jVs`_cL9Jn$j)!RXWcP-Z}jXhd8(Y#Z&3{0A3)PkwI96 zoMRa>cV!_=EaATJYf=@p5u}EyAg_QB(G{(jF0;(=PJ|W(6-X!%F{ew7C=s0RTc+xE zhlxe|D%Cta=rGw4~S zlF2Bl$AS@)fURRaa7d14t)_6?aMCKU?ouJ2_(#6_KUG}7VCD#sav&x?*{i#Js`XAM zoNFt~DY2obqxJ#@ z-Us8?;6=jgd4Z|p+GW=l@MNC1t=ygTx6Aq;JP2H3qzi~IVSV=-o~Y#&iF(9v-V{(5q;{RR@4012z^*wf4=?{T?>R0Wx+s?T*t18}7xNoFajFA@w2lDJDcIt$z!Zm?%#yBaC*XS+I==Mg~(ytdA)Qc1)nv>lDi7h z%>UTG^W~`J_;&Ja1v&dMfvH2Wzwt z#*WG^j`|RPw+NM0&9~@)SLBfXfG*J&jFPBWv21j{QpyhZ(Y)yjb?K?oA5rFs6M14_ z=2E3t9_wJyQdSfZ{P^E|yADL+wTmv77kCbfsUNh>2vD3~0t;U6x(zQ6pJRd^d(GR%oV$Ctwi1 z8A|8`q^Jj)8*O&8U!R{5D@iR6Z~>mVBWh3=WA z_gIWECL+s2kA^%O_fBQ=q6#I`vhx>4=1VtsR{C{U5xCsaRmb=3JX=Q>*N-1CtXJ9u z4OJ^mXlOL6d_pkjC?2b?@JVGde1JN4;nez*oW@HGoK-mdu67B`I zI?oba=vB4hi0m>4%ids~L>zBBKi9caO1+U(G|}gr9iP=T{^uh5MFg9$om1pQedJo( zK2}Pta@66>PpM7zr#(>MW>~lipS2>Y&oi)oPXus;^fD`VzvjGUXe`pP~4|SZ*A$^r=~EQ z`$1N1JSnz9A%CYtsanHke>9fx^3u$LMkhDnG=ISpDJ5~|-GNSXgL8ejC}Heab{)?! z>3VzerL~Dg!Ie^px*#JltJ>mA?$adMxOGr3QLo<3e65DW~&A8&rLkbZn`v-Dmc zno;2KSQoB#kMZW?76ES*hM*Q0<^n*A`b*W;z&>{>N1MR}^v3PYu^K?(h@SZIE0r@f zgWFY{{@Cs6j4)3;U3mM=#V6+przYFox~ADU_ERq}P$nSgToh^MZa%O9^&9q7ZP3O? zi5^2GmsW4y-gCWnI9*w;0rY@f`t7lJ++g&-F@j5>Z2>}dA$vS-XI>vjBt_+t_@s6a z4dWVho>gD0ct0mIy-F&Tt1BKuJNs-6DS5G4F7OfXK4?`lna&*5_zo?!0!0UwTm3pA zdrnb-%PxzZ^7y0QL(_&&2R}%;=Zf+(V@qer9qS zqMHuF&G+A5N;qF^73@ov(`mF6{;D<{P1EUoxSX09{Wg>#7+qgyt~v&Y6UYmgy6gYi z20rB*9$p{Lnxvso-%&|rvibwUl_h5c>^6ldQ}io=&%2`;a@WOZ_w3vPnNDs#%H+}; zIJg5dcipXxms@$r!~umKJT_ZDT;ASQq9H>brYRsN@)d|=R9K1*BF5}Uc7s341ihaBzekiGFUc9mp2B}>x&p}3&-g1>kB+%I4X3zJM+${?nUx> z#-PiHRbr#di?30P$ZI(VFWWv&{UmvW|KsiOClktxshE#)A3md>jhAgN)KbNLwEkcZ zBar;b6MUiFlWu!BF|*0;Vd)ClTi#-&q1>`SiB4-Gmb|T-5Ontx1=%_&q z;M}>Z(pyGMj9?%7_yOxm$94<>@=^k+)ff7fit)`cf!nvTb(31{YB*3?g;uNLb0&}A zTkNs+NTPr-B*Xrw;3oUyLI^N^U+2den#twaa?Lyls5IgzdJNW^&2|svR7QJkXuo!u zRc{kUh;IB1GcBx8eo#K30-GWYWLm(l3ywg zs^>v0{fHQ8>H+C=+Vv@-+tOY%E{Q>pLgIt+$8bDO@n^E;-1M6Vw08lh6kjKL;SZPP z+_H9q#m)qd-qjdfi+i?L^!l8o!j|N#)xWT0Bs^<}cp>#y%vl4zP&ORK2o;LLrAbFA z?T>Cn_Jlz%%RF>9bziF`eRC6a)&iD6jdD*rK~?oopui@b+g6p-cYgQ#;B=hu_3+`R z;xlVp=eDw7oM4`EkIj}alFJ|JwUpN=o{b)StZvyi(( zF?11?BoTzZRg2LeKmYQ+21IJiFGkJkLL8R99q(uRLd!dkMF^yZz4Qn{xe;YU1%i=J zfp2sXWFiw|4>BH=Kzh7-3t^qlDC11BRcQqe%K+4f@?S=MkvLK#SMkm-j;D77nd8p5 zdN!S+_|`HROU}+dxnQ*hOiD(N{A)POCOK8rEIiqS&;1JquXFbVwmbGQn_0nNLBvm9 z+2M$I95q!d9c;;5*0?lUZSo4(1}m{-qgfk0?-t!HA>$Q0xt;;43bV`9S=N_4Bn89< z5SPmxklkl9sMG+^(%r~|9A?iIvzOsJOU6lET`F>4Rf0}v&o!^M8q-|_Di(y5g24AU zMILa7N2>+uP7t{)3BBH}9>aaHr=)Cq8~IW=zCC^lKt&g81Mj!hN><6oJa1GWTQ7>tDpKr^sBAQG6kNUCL5-MS z5e1}tf6VXLhgMr9DobD|ABKU5qaaJK1=sMCF8H+}T%%!aju)=y)NRu_3}05|q~UA_ zluPaX<95Ah?vi}j)GX~|S3MKwBH`(dkLGQQnP7@zSj{*QEMh;xs4}>T5-rg1fYEooom5dX2pLmm)yW)0l)OS9;3@nS(;j-0t~LB*N#C55 z3M)DBZNLaImOF@B9r+%^ARQ*`4MA(%k(Pa;Owk9P!!C0HK z4)E;)IL6?4{wwfbT7*g}ILQFgv|R#Iy`08wTXMPcipOpfbo%)9UUcJ43w0!pA(Rt8 z%0jD}A?1x4tPguhYa3$%_%Y`}kQfXM^XfL0yu7Nw6@$+c?wak+2G-11sc%LT>UT;f zdhJ4Wz2pZDX`a-`cJK5cMspazqMg}oaG8-i=Ju9qp`V{5&`oCZ^N4~zdkl|aKd#7^ zNOQBG`x*@ADQe+>L(+9MRFW~Ui>f}q4WD}asfx``V29N4>CFb(`@L1A9(}9$tJM1b zcx$f)B+ocHJnDYp1=p=JLdssb{jz8gTgff9J7N$dBbYmz|7>-aYShDMG|SuBa+N%Y z()aj`0?4rl$BS~CWWx$mQ^~kc7fX${Kx`oxXadFC2WZz-k1BJg?(=)4QS4@#s~LA> zWm8h_TJ}g>K)aKN-UF74Z%eJ+LocP>swl*X!)*@KdGTJA)l9hr<|02F=ZeB}@oRx} zRldbrsWj$rz`4$se9y1Ud(LZkX#NY6Cuh0I?)wgnT1gYjxA2L&GBwHS4wzD(4#vXU zC;uT-W8N-)Lr^bI=Mnb-kLw8$+A^ztv3v+7_7LMLw2DM5S((Y`#CA!%qG{jF@y@^$ zLrn^(-u3o~^}cGM%l_@7eZFLTN^W@hmpRia!y>SxNuN1iHi3u>hF@nlOqEkUh}++A zjUB)@y&Uk@Y8KKQnM|Xz2L!w4)`^8D@yiQHy$R@Qrrn0Rrwe(aWH}gJrC6KN zp@2ii{QP*mfi)dQnR0p;{B=s%T5dcmH0~Hf7)&mKA$YR*^H+g23ZpHCN(kOF*v-Bw zH2$}qEaEB56zk97dvifq;nyPJJ}{jqckTf&zk*)g$Fk*iFt?lDYEn{O6f&T|oGRx& z-EGP+8ypF3FL<$hMXp`=2!r4sG^-qnIi5Y4|D1VV)$^QEdr<7Se3fkL+*$skow@Gd zO_^D!qPgTg!wj+tuKkqHE-J}@`k8Bx116L~NA)hP{3!WImmB{5W~1OT53zDPkd zmMc%C&KczwtaT{viKG&&#j0fiO$I#4p~1=x41DNx8lUYCS>zvY7D_+N-yzCXo|g-d z*o84&1*1F*iN?Wb#=AsGF_7lS<8fw#cZ+(`)&~Kz0spP8*Q`#bwPaYNZ`o23S6Sf~?yoTw`9A zspVK+ahmJOa~?PO4Xm0et%$Hu3_8uELFOH*M}8b{KriU)KI1mqft`LTn*S*V4A88D z(`bL9XV3-m`x+?KA8~J1Z8@~C{jLN0-0z<0Mz0$Eop%lWi?%qA!xM=h^;D!Ph+AA<9q$H=&zN#0N2y-f^sm4fUu2 z?dY8LqK|V)M~sOU%dVH-zEZMOLX?E&w4*6WJj$0{1Ww#6mLO8&{dkg^pCFZ=xjy*x zB|6-2Bq=`!LD02Xcbdb)^Lj_y==F{YpGOk}8D!_a{={w%PnLQ1NUPSw*1EY`%H#f4 zcI#s_d(*W%OR#UGu@G)xFbSkG<}fKgi2nx3T4lHB!^3kRso&0MrXbba5$35`l$r9o zC&khzmwN9skbpzF>NF}vC&?K=v52Pv7ez|=Xfj#c$S4MtEaZvLV;8jyr+6-;#W9VM z#O$*T6ErHz>d57JLJi%VnxzgAb}HS{e7Q}P#S?`yQ&HxjbjsUcSwGx+qfOvmI2`3k z^F2~(CW{jCy--te2{N;CYRy$yw7p*tpdL*2~%i|O_@*U zeV6)IJqz5f-%*y|NkQhs*LZO>d8|DYH{xHL+NP12T=^!`CY1Go;<(AnF;hiqT8%Iu zPq$T&4NFdCE`0BKeT*+mXF8OhE{EwV(j5XiEBHQf7`WPKY-L+gsbm5(`}GN@7l-46 z+I@BIvoIGm_v9XdGTl!oDDQown&CYH6JuNuf$L~~C0)8P^nzatgJw3GdZindOd3gc zK#Rp4kT95bvnY`n89g{}g8L zw-_!u#=q8H)Ry(Nz%qwS_#)_Svv}JSVuC-Shbf3d6+!Y7E@>oqQF}T0f=)QsTV_ww zE#&(JBD7u}fo?U!9{id8NyBfK4I7lA(WDna7iQbYNn6PJSe{o_W~d@VRsIDGyh=BC z!;5JxIVTZQ1miAc!JK^swT#=p}Fn(u8*e z6Wyk4nV~d&Jhz7To)$8RSb&eUywgzoAfyz)j=Qzg$OIX#nlfdK=3S$d`TTfO*;`mW zv9!KPgW~zI>w*+W=L)6iQ`Y&x;LJ!sficnHBtZV~;^U*0y7|#=erWJn2+5oaARC*& zQb~CryTN(n13IZW(2{j&Xm@VJ@7Q2SW~6z3-UVz9EZDt1%1txa?r6o;LSOjHIF+R+ zOr!T1X;EZIb_CYn7>8kBb7FHjdAWG5sgsRxYBXg|iLj}|jxaIsc)qlJe)VW+w#M_J zdEm@4@5S_)=XyZ(`8bJ2b$+2F=}`+6-lVM|Swj69BJV)wq2iLd5@nXsCX&wDZ)6?mcGa7%4 zr|Omq>kyXrC6b3=n&Jv0f@WRkMRGF$2*r!H=fm#z-6b~pw5qSo4w&aSCK22TJm}6d zz~{T>!f{DMZ1(BjZey|7BvBanw^lZ$2W!BQ-Hxet>b{E=alX@Fbod3M@x7f!T@|Sn z{}c{}EFi8qJkt|q1@A{&vFwRsZ4TJPT75GH9X#|zQIE2SyL27@8*suX{#*hdNg9U> z>I-5&}@S6~AVHXUvA$*`|jVL=}v}G%^H)$$Pu4b5&(-$FkpW zP&~(wmQ36Ttw-|H04nqf1{V)=Zm#~hy(T}Qu|ii$g?sW(yf;3DnXr zmqbv);;ca!<$80ZJ2{wf(8a6Q`^zqF8Mf25gC0pU>9jx(o>m>KMmt^4=qQFhAgBSL zLaDyY@s!h1y?SnLO+t}{itZLe)(j{0`-mCczw@LlBbrI<4Qz2Fu`DPC)cHL1Hah(; zxdPm4PZN6SVfruhUq4fe@b|(dUShb3+0^VYNTT5N4tC(>xJIrF);M99p00oJ*{%X5 z^b*t<2m>`E^R5|T+sX^|eu4K);g3ix%V?F?X4sdud3Z^(V<`e#{&T2FYm6yDIEUtz zW}O!h{I3_bVbDmTTv|zK;FUEb%1ssw&Cy2QUm#BFx=Z2xzpn*12bJ3U`TL_=T3RZ! zH>`SA$TWtPQM{SA#(~&)v(IYeYuM{Fz{V7d#ifSDY!VKlyVG%yuSRD!p{YfJ6hMcd zXO|cx*hqkU2^C*7Xb9?WCSy4A;qt*uG404U2Y2=Xh0nC@aakR$um6;w_5WIs!eZWk zScM=*Qek-N!E7_d_8B|s?Zrh8TwaeK8Hy*|&ZvR}L{TXE3sa1OI_ulF*57$tlj8_& zHX_Y>VWi*^<{JBj5EtI0_4R#cx!=t!qZDUw%d^=Y6hw4VAud~fLzX~Bwc4iNf=M2_ z5$N4x>h?jER%Vobun+O@z{jo24r2&2PbYl0+0ind4Dz;MZB6g&KEQY-6k{}g^;7>3 zxiIDXj8AqA4B5Vqw6*h5j^`ipj0S5|2K(@bzDOl=@k@Qdj8UGu{(6sD&c+!4Uthc& znfa0mwhpfEF~54AvD^$W*m(Dj=9%Pc_ACcW**(2|D8uv44O`ghANm(Azft!s@EjPP zCf7Ms5bv6Er|#TxE+P;+3uz|7cvA@*`9@Y&z8C2wOEBH-bv}lnyKjU}Z+#D|srad3y$mtqU`(7wANAWj0ez*85#cJ^x48`D1*6%(? zvq}(S?z^!q3$aBx+W2hvqC_HXaio;nmB1m)&p=cN&7W~_J|JV`*InK{cu84gHmM4C zYzhD`YtoN>5VQ(mzeKOzp-p{v@aCe{cGn?R1@nUW!DMp|3m6(ukmngk!zW8kr8b*> z0v=oXpE6zGZUH}n3s}7OUunzf`iXrOOLq}vX+S3m#WQD0o_B;@-!Go-t10K1Sl_Ui zJZ)e>Z0)&)sTtMrVOHx8{RE%ipsWf)+$j%st=!i@SFn5@M|d4)GL%kc&gq9vX&n{I zt@QIc=A1B4Bkj;~T$mDLHr=s{f8SGE)|(#Na{)OzDJz}Ur3CILD>CS%e-GW|4Mj%A_8ltxqHX5zJ?#99@N1~KP^Nb zSt==HVAFvq0!c7?rXHW_M z7C3Yor3D~UktZ504wdMwLjH{g+7^7@hXB7kx165b-!hv@w}Pktl89~=l7?c2X^OxX z8sSK9a`XeG?AUPXCo^>TiJ<;U7-k6g0Cb@i|74S)1ao=$DP>%{%hyyOLyy`5G;TqgH+*A6cO9~1Nk6`D%q(d z(Q-eBO5e{djirgs4X(PqC$@|_XnTe(aWh{wJ;r9Crf zqH~cY64`ce-*N4A6WzKCt3UU__P0}4cQQNstIwO~bZ;i!fy4mf?WIeLA$|Edt&d6z zi}g1%A54p_{s$Izx)zkRO*5%FE0wcR|7{2|N60xIt*zi8KG-qL6!T5wC6f)Q(nAuMbfaocmaUXSl*`FD5jjP(Nv^f!JjZnJ12}3+CDf?jt z^`7e{gajl?SfW6eFdSc6h0XI=Rz}FW_i};kaEhV+^&DFOG8;4sbvozsa9dGi>5ATA z=UBF{JVAwet0uS78P3Uab!t-&+Y7dJoGh1P>YYj&vvpe2pAOP|aebRXch>|{+2s6! zDmHZ8M5-3BAp(VJa`}ruOfQ?i2#OSb)w*QFb;h?wB=e&W_77%J8y$=xg`<#OVw);B z<b}`=~s<*ov08*K-z#;uKl*vr_RUZb6 zoXi5WTrTx)w6r(IG#W($gV`dd?^bk&h~ce)t#)4SOm2}6)YO{c;)R^NTf6*8xihAX z`CRbp6tSP7Mi)PuD=s;&o?z*VVjE0mH~Nlh@N=+7o|4HjH0M zQrf<;fk0J~np^kSSF^zWTPP{#Sl~=f*(S%67R_faL?Z(B3$A%nU*gf4WiINlH?Fss z6`TtZ7R#?{4^VSDIfKcSNKuu>rF1vmY9yAHsiPP*lk1(%=Z{Ch_s5xdf{#H1EYTH_ zUPhpH4+2s6zrY+H7>EQO?esEi(R7-NpeHjLoHqm@YGQ2(?H8;h-4dSigf}P})ZY;x z8vKVH%Ys?HWKTASauInN1wv5P^%GwRd!|gf{k|RYQeq>CEG(M+m7`(ow5gR(N+NG11mI za$K7vHer<3TSJP^f5J_CNO$>2ccH`1t2SGcwCM|K)3hF6y+rk(yy?6;0O}d;#E!dn zu_!VjCOCtReYUL*zRwzza;k{X--rJJTK$1td0Rq(4`oNR#m_X)N&BG@@LCtYGgy;E zZ+*Nf7*=zf=p9}(o=$;hHtM$$k6}(`QejJXxR^?&^huxmGzkBnVCY|%Xc8d^a^gLb z2m(M^6#g8F`onbAoT37`D^NBYqOr&)=1$km8V# zAoc|;oot1Q8ZXgHI4gNWiGOVmr)rrSj;e^xSMS!OQV~575-q!G(qpKKZuzbHTI$?p_QlKR?ZnXs|>$q|P$ru{kzC8-hD z2t@VQN7Io=(ym8$192f34FSrOYOBO*f9-Ss`Nj+(0Al$tVm1%W2(&G3b3F4{YFI7t zFGyvz;44w2DFE6otEtP+wZQn%0wNoX71dW>iFOxjEVdiP*Hs78McFg+CUb=p?gVuB zET$7t0q3gX_6Mx8rYah`t3v?v^yP`bLsrFL)82aHq7|kQ9^9MTdBbmE_EpC{FQfJ0 z!^}p}@6HFBwLY`62L&^`mGX6MGIjqj0!9ERZ9)R^1BzX(%E?>R$Z_4rxs?6AV5MGP zWzr^H`?qzdWVkQEG3}Eb{DQ`-E3H>&;3%T#kh{rT#x1I5ScDC5=#-KGWjr4!KpQWL zC7<%?2FL+lOd0X!+9Meaeo1O-YNAp(m;tSATUD9SO(}YSUdqxLTqhMzK<6vu8Kjg? zj&<+o+D*1?T)N>P3&hiVb?09!65jmh!-qDTZ3CwER@T?8cPYuZa3X@?E z(1SS8Gy>r;n@IxLCQ!e4GYQb63stXGug)h$7V0fe4ewVs9{~o641FXE#%X`_u*^W^ zzlj9@n*N!;L8VOo56seT4|mZB_-q|Nt%{?eQ~L$fl-r&NYE~n0dE6iTPL^9se(32}9`<{s)+;|*yO^F!h1GhYU9!#A09ggm z|98gttU2(#uEbG0zf=8Tg*BYf9E9*AA30jBmTwX!#_{!q+x}qer|)3o#ZTWyj$mV; z{kht~SQ{RT#f182*K~GM{B%yo2z+iABk^3vjlM`3ARkzD&{s4$p!k2xP8-c1sanr> z2vYbqwoJ7lS|B!gma#)jLS3QGDuT1<_wT)L&aX?9GVjH(FNL+UB1@tE3vmB?Y=}WT zQP{zt7WeB5{j3>;o$?!@{#TYD={B0Ajvwa9B9fFCt{q%8h&6aKw@fb*{{3i82h)z9uu=>Eeq zP!|A&NjMHj{e2&NFv1|ay)o2~S1ti7oIK+{zK1k~wy9wyEU(&b6t_^Fch=h5zrH_xDQB{d+H` zh0y8rBLr3(?Dun^a>)e8&XkG;<&z?k;J<9K#0hu=G zUps*Jnm16<78#u@oOk;)etxseNf`Mvckz3|AAkHKsGxI6EU2f zoC+f&KTr+z&iy_^!nyzNDYuILdt#TpB+LNU=&1Mp{ZMW$ zl}Mv9+d@Sx54Q6hdpzDvDF$fRhILBK3FAlVE3(Ua$N&0c4#DWaz<9sc!J{1hgYDz> zd%RY3&Zc3u9wChP6&^Q)GP0K^J8yYVvrj33)aM}gy+rw6qyG~hFe*RW;PSx#_`)p! zSkt2**eMh((x8!4GN^s?do74s!c6_%?kk1FFI({(wEj4?`_)4>0{^gf`8(Jl+dg_f zp^|d7S}29R+5T=4+-2Yukf5&Unn_aDSM zwm`2%*sa65p0twa_^IqjP4XwGfI<#`8`sG%Th28&22h>zlHKJ&Bt>+>!6z)8tcDzTyT zU=qdGtav;Y6M2C0CzrL2fyzj!T8epnvP}L_e!FCfP%MT-zQrlH;!7Q||3+gd7F7bV z7@jl=pbB=a>UIwAlu<(E+r%ctxrc?0op51Uk&$AGlX$?tK-aE5JTvF)twUe;_l$ z;!Q#pafde+Bxn@o!TNCUHN?zE*2ky~TXWuSWdh+KfFnS|rGG-7o&4{uhRv@dlJ`Xj zg-rVUC(D&FK&q~PXebnDMkEg8<#U0+oina)R$9K<0T1X9iHygC%GMtIIRrhgN`LUn z{l#{h!z4uBlkCyWM4_Bs3ahzE))odX(|xU|+{x%gjlrLOP?LW_WrMi)oMdT!1qqw8A%re8izZ6^b{k3fkcB`5(cfJi35GQ zvyJ_PkvCw#Gr9(R`&PSj^cUNf1;3G@f))G?^_HgGRvp5xh2oeo@)%{us;#d=~T|d2naqnVz)IuZF{b98u&7p&RI{<3{X#GyM)81 z7!Ekxxg7>-F9hyd?E{)M}M3PFeJm+eE@=>Ay zaSUO~@;M;9#(79lz+-GmHFmC2Z?Zo+7Zu@f#xje;{vakW5a^V&;&zWJZ8Y=*1xH~h zz1jf7!T(#uZu)@5?raPha3PVOFNWwIKG+}6gag%FpTkp`v*B?*jbETq!R{2*ktmff z*#*^Bk1-139@EA7UesHy-keM(j?tR>xB$Y1GU35MyH44Knl_a4`%8>0vC@H+YDa?M zB=%5`hkbHS6%whGIC83hLI$wXVxB8qJDFO6+yXs+Su+r(+>=JL-rp@ilHLdNqEjjsqaJB_AQKDA^Umxu zeFIrq-d^XHwF$1~L;|{Q=2XdQEhDgkwa@jMAROpes9^!eV?7H!xLUsdX)FvRIei?t0~2 zP(bc^6lq{SMqaE`k5Fqio@TSv&tGdYJ0tdFejbrZuk+zpzq(Nz?e#m_P~zlTcGt)J z)#}jI3Q=VD0m_4vlwh;+rN%;;%oS$W8A%Ub`A_%l-rs#7yTfr37haz+!ts~_7M`y^ z^+XbA8EZYG{er%GKH${`JqnS12bj5XnJcY(N;j`2GcAqIUnb81ahqu#W-NdO^wp2f z^X2J4Jzp{zcJ}soS)$ftCJP|pGp*zOw3p5;_pM>JSn^xs%y@aqg*aZS^sR_wL{_Y+ z{eNtoby!#1y0)cDT0pu%x{+?AyF=9KZt0W;=|(!GyZHudt-a4a`#WA- z7k`NOn{$pi#v9Lbzb5_4h)r#eRuaA8gzHY1xj+G*IPiA4zkA~jpy%=?!q0JTvp{#A zJ>=vr**9+^|l8UJIB!IZ1=})-&r{ z(7Ont)Sgg6i4Tdhoa=61QE){Z_oj2DW8IgW2?)O+&+*|raJkPaPQ8u3=VJ2L_{W^n+pIs7YnKR4YH_;%wPf&&JKHOcYws}JNrav#PcLx`|r$hP~-ff-% zzi4|Xp`(ei8^WGBaXoxmzV>0aJ~1N9X%gXha$gP?GpWMx$DHgmn%bV!XU@HPw#Cx# z!WW=yhJHrbqcXgI>3N7ras7*MkS~4Zb0`bDQ^^s9KL>^-MTBICo0u;#q~W5HX*&A| z4BBX3akv$VV=9z1QB*|HpLy@Ow70g?q1wkbd$raYG}OP=U{sll?^nCrZsXJZMm&&0)nI6Cv&A40#MY}V)2^!Rs&64`vzVwT(iTR}Rt$tib#uBxbR zzNOS{YB%W^d z%Z&D%@6UA=I*la1jR+?YC^`Ig=b=lhl$G=I?t}$p4ZiJX{fFfuc5C(WyqA0kW>RPd z6gHX)+7$)@07nqdsNY)RK6iMBu6yRzx*l;rwA54_;WPdka- za(uKr04dQERj<{xpE!Jds9LGl^65%Yty}~KX>>52X{rJIH#7${@Tft74HWVzno&Ez zC4&Aa9rwnLw%93^r^coq1N@$>M&vgB>m9F?wFaKAiO-r`xwg#pp0HePcLhY0&p95$ zL;~*Z#AVqYN9M}vKRy~>=$PFvaZJ--D;zGhIxIL#AL#sHiVSqU*i(rgNww_ydO^!D zpx0o<0mRYi>g9Ddh;AtpFNyg2ROR1O`Ay`>n=+(*XcyWzA%EJ6Gkj8ZclVENs)_C2t^QFSL*GaqKQ!Wq4!?5JiSya%o;OJ6^I{)X(#@*3yGWOjCRr*uQXUj%V4pcC>wt4`F+;_`f z#0pXOwmS8oJVgnL`#O`=5~!wmZX12*7Y9nUR*u$cbuPc7?7fbD^Q!?|4a?NqoZ**# z{o-=)_?$L5vZ^cyIm223e6Z2-pEHu|NF#|cdCS6>t%wN=%4xoFoCclsSd`}Bm+W(? zXwYdDL~H}cfFf8|u>*R7Z>Gl=cm+MSWE+Q>DucZq4ViXvn!+Ox5>{TCY@efdJ+TSy z&gZf{FumvDal0&8*z?sgPZ*B5X^GjTeDylO=T$^9v(M?)aK2f=)6F*V#X3}})h4Z) z1x@l<43oz6c?bGyQ`i7L`ml0PCn+EvJ_z-Bjv;@1ZI3kU+Tl+wx2m4N<0zWYqNdIS z?R*Q``~Ae~lBgPiOsLa@kYPo`y@W`P*KH>KSvBf;FJJQFFzRMx^NqnpPfp3Qvq-_R z=~#aPB`_}v=mW`wH&N0k2OGc`F6)m%EzHX887VH+wd*4_VfJK6klEkC`+7dJSU0YL zUbn)#@oJ~ACWH6Oeh#okB)YQ;>)|ly?i^v0lb)TNC?zSPy%s}}OJv0g0QPQk%FnBv zUR-|Oeu|=)CUO}quII;N=JBN$II_B#mW$Qq^}A_+For29l~iL{g3(v3Q3j+E)Dqz- zC6wXfO33rpva%Lg$y9RMxwums=vVv8^{Dvy-Oaj-HoGY)30>0OPD)%^54~<(&KXsF8p<2;sy{NICGv;GoQ#~*T?S_% ztw=s*Mr#>{q(l$@?EyILO9;ctLSCZl$WUM)`>A7)B}u@DRy_XVhh_~oJ%g5!B>i4g zZ4|~wMl6wCvBxUNqom;xVILBYDvN4$j5?)ArEWSHi>mtFn4a#5(HhgEEo_vN7!gpTGiWcqOWXaVObEM83?G_OQgc~ zreg9+4Kh1zthjV7FZZSkOZRL%BV3lk91#d*XFHMyWH(8KPkAAxG|I&4-hT_CKi zS{w!1rRDN$aPn$yVbA>_*I|Q4wxITPFZ_Tv_Ovs~?oh-tM5sK~lq`Lf#M)~}RI zeM7R4ei-sNojRMm2!U2~(-vpl#H$%#4t1O=`Or`r*F9#BDpSxKA()<05o7+5$6TJw zaVdb$io*AbGlsY5iDhrQZsl^I;}hW)Bp;cs`XCMy zyct0!a#S{x+Q=bhPakE>d$4m64xBnPV`FOJK-2?Z`!(bCy87;90@?Hqinp8z3l z=hZKHCe50lPxjgl9U)a(XV|nqI_ALS@Zot!X%#D3I4|B9xHD1Xv@;ho9Qh?}?OHpz zk2`@iwpa0uaN&<=)&~PUdCj7L9t0JLGBLJJty%#!M3jVN_G|k@_Ut4&e`o&&$-k=l z4klGd+nvNR|ABJ9qP%karhTYTrXEl{UDqZp17yCw#Jw;r*10xNy4lqIGF@fyv>5a*7ER0z&Jm!z&I-cG01YD#WSgx6c> z)gP{%pWJDs62u)|)Q_lw3FDdzJ~SBjpA=DR>{r)*T5Zi}yK*zZ`%^$?{G4sE#=%UF z%QGWgTf5pf4&0U=L`C6~;VHerjzR%WC(+G;xXcbe*l`Tb-EN7xQq<3p@?!qB6OC9{ z45!7~%OiZ(p)TBU;j4jgUY6JGmOd`Uu}2m>!$(_yP(q_m{lj48!{TfupCyN0lwN9} z{h#47BxaWVk)tn@SQ|fd=ROsAR5<&%WGJmjLzGfMA6>H8q|MjKS=WXl>e3%K*&yK? z>&0EJilEau(aXfsr}26{@?l~Uo9-23daLHj-3bN+3Yc4m+!AqrN)Y^YiVkHlgk10Om z&`AlLj)-Bn{K04^Hn7%D<2Q*vO5QhpWjsb@fu_=Uga62j25pzf_CX-lh!`yaVHK}$ z_|s)?g;>#)oafW7E6KGlhmSg|k}otBa&b>FFw9JPn|GoT%_q|zxSWnJbcipb9asYt8OzyG(!JmJFsBpE zH)jYYb4eMD*3+dL{`N3l8yWiK4jE_(Bdg>JVrbXcXs@|HK{IVeMJP((*eb3D!JI6VP!o@)aV}hebgW+#(SqayQOz6n2I2U%>6jQEI{fd^0qOfd_i^gw1NOH%hjI#`Ul?TMt}6ZZFDSRRMT32Z_AJe#z1vf#CUu#5uF0yxg_6DERX#0erjv zw`f)8Ka?fNzHNcnT;Vt-Mj6>Kdwi7^%mNrfixs8nEnkC2&CY!$U3M5eOY)gBTRKc~ zC09kL&T@(Lnwpo1-Y!_U!%(zrAgwcXETYRk+yh8MaXzk z#&n&aF^!-D-gFo?u3n?y{v@`AH%2*AE$KI7XHrJEf1JqNIx$`;5eiZC7fd=_I-{)m zv8*(dc>^64ST1>DBrYfL?s)J;hwn}Vf%`|2lqU$PqSzaWmp-v1K|6sT{}A37m*kQL zlfqNFtABn1{wFY)KuZ)bCo-l>wZD_E%V4!XtwN!)wI&pbuTU}cHXN47D_x^Nk$iRZK-tmL=WQ9-Cn}udme9R`r0S!!aEryot^y3^gCKQ2l9EtY* zcIcN!-EyHbfLf$_37}`$ug8oFuK3_-AWv7;Ut!vyCA9f29xiw(dIZaEe8Fb7cg}C1 zCBf1B3WaAPBkV=LiF9E3ORvRw+}7u`-@nZOGyGj}J5Bfit5a?eHa{NnMlLHeH=I^` zw6p8!+1gK}d(RI)r-ctDi6yDrbuW&D3?g_X{)BzrLACJldTL?cT-StMsI$$zIonpM zvzcQsGyW^>2}#70@9eFTOIE+1Q4gaN8(#wR$rL_?s}~**k?kmj#4%u+XdBDOGL#^SqMk`HI9fbMY z`||j%R(YjbjbS&s-q@@}yD6xaco-pPgviI~bB?;shLZK0sEBN9DOWx(xu}pkD~r!A z;dUqXAPSO~{-upIL?T>4qzr?CpO$Ejbdp^JL)yzAUPQ0g>_7hQL8+DRU<(J=1i!r4 zlt>It{x`EebjNLRs&L5bp6GCvFGpj0x+fvf!hSdMoh< z0y*q)sf&Nqzf8CG>#|0!syCtaP5U0K<5yEZeh6HVa}^7s(p4CT$3Rr#B&zjLmo+>p zM}7Oxquz+O$mpsPVR$!lACg;|g?U&=gA8aO(8B_1ztB=0GUHlX^1)sHaHt{NT8E|} z*ghsSk|V&)uDb<0anG5v8M9|;7_$4Bf%4KkTL6y{Soj)@%7OElA{9y683w#Q#jEt_2tR0LKir;o=c=XO#I)C2TQxpJ!HFfe?w!@u z6%^A!$|2U6z;UZ`$uidx2)Ij@h6JH4V9r9bR&3rnJ_!eA#QHXbf1%Ky5WQb{JXdiw zRS}Fg=MVEGwhg)wX`4O`ecj)fn8l*ME->)bqROb*>>Ho&q!B-}n1oCuGlayDOp%#Y zC1WOo@SBg#?JR!~vrJ>ocRhwpqN!!_+KjhL{j#mUx6B2d;rdZ-jm-RpL-->+o+ zfwmr2Q|V%7Y$;*C+C!qpLg;S#H}u!K)7z3yp45sG=H1|V@**z!oR71PY*1Um_>_lv zyTNZ<1a3rA#EIIv>9EDKDg=BT!{)AWl*7rXjfsOi-C^HaP}J4X5Gx-JctOYe<>-+< zB&pWADL}|mJ#r3V=<{BL8`ncJ(mlejRDN?$p3!jfo2ZeuDDET%KELzik_%Cx{Rw*` zSclYCsSOp*eP>7pV%q33-cxg}Cgkp)vgN&FVCnhA?iX96!T4$gM52&auT` z9X+H^Xg<1~E&m#rX$^g|K=+?gnz~6JWAq=TL53kp;n6&vqB0F{T6!h^aA(x{=IAZ z+gef0_Qh9T%z^=hMdV^*$~`?76s3us+Ks4=j^bz@SmQbN@g z7w9Z9p%EU}*6lc=GATbEvn}_|%IsLG!}`n>euO&NF8oLe8@wXq-TR{u4N$LMRLxts zMc$BMcn&YJ+CtpiSG{QCRBYa$c9z*4CWU7r<&Mg$d zR-6QxAnD5==v&b+nKREM&Be6$4%LtWSma|>U>m6kE!=CK3a_>{>qCLQ4o_SXZ>U*w zYYGXEDc`;jG`9yo_T#8-V%hv)tUI|xtC_Xd!^ui=#*pWZKJ&X5({GQfanPYlNWG8J zK+aYqXl=RC{Cs~EphX(8=QAVjl7_jH-qu8-S)io`XY6UbIJ6hP3tC7mr8|@YR1@ua zhz?oi=&wS|J%9pYMTQ%DMxHn;F{zrs)2XY1Bnu5>``M^+I?bQEs%@K#ebG*XDB@^i zy)Ys!Ix05A0U|YZmLaSZc*@i$W{K(on|C)Z|}_llf} zV*f57=KnLRpM+4`8?HMDVcNd&<0>DMmr^j9y@_ac43oYvx?qBq7G{D6*$PUHacbk| z8+zP5CD79}4Ym&9+ruaPNzjeOHNEYP@y^H6qSgH-EPn?+Fb%H1R5v%c?TpL&5<7G6 zJ-S5C%$G5DKMn&L$m~~-Q*S#fD!oEyDkCVRR*Z`{RxOUcBL9gcRtb)w8IB(O-x47q zW|4NVjWSc)MfPULpVK563w$1ZO~!>HN#eUVi&$VBUh3jaXkHUhK)$zELh>2~I*Crk zHz;@eSNb|k(K>_Swz0zD5-|-~!h}CRQF0Vyiy3r(~!cgERr3HM-FoSsu zMtFkBLSwkvd#J2dUxPNct2nEvLK$Wpaa9HQth`PQSUj42{U%p6aa5a5s!~mji8s95 zt|S$r-GbMyhuZ}?#|jqxAu{BBL%JyN{uZSg+!6FzRYfrQ=%rI>W*A(g%<@Z(7x1fH z=q!gIWwp}6tT_XgzRC6vEi%R)^as4b-19sp#|DQXoYLg=HoMB3qB;QWjTJlkItm?c zK%S6Ck(l!d;Sa8QViO6O?Jlb+JcY|>yH8w^(Nzlhx;2h9im+ZKJ^WsX0aSy-wvvzQ zJ{B5hNj$4oShq)jg-;p*4Gt#dakNN`%dd2951>i{f>Q@Gc>8$EuxC5 z%PJ*PF+H^!)ts04P)JsgO$Q12&44mU*-9?%G;74`VJR)UW=na{fF#DrmI^_0Aj35b zZ|^adE^cCkkk|5dDDknXBPoPNC0BKfO*n=1eq(Xog~UybR%7jWwIwmAPSILL1PPk0 zukFcd`EiwfFCj0CqBE!VbU&`=CSV2+`P~>4ay1;K{V%~u2M$C% z{W=7fyK;9X4yHACSg2BV!KqJ#39Np!40Nw>&eW(x*$tbcV*nr7k)&h3;?CKZlrm$X z58nNoNYfN^m%sk)#EkiFv=#yRcIH*1DJ*hCW9CZStqBe=%O)#%z4t>>$17u5L9-s4crRdIuFxyU=`Ni0<~*cpf zR$E^u3!wJM{_ktxgVgsI%F<5L`K5R*K$lu>NV4Sfzm!Sj-no7vfheV@rgZ;Y&k%Y$ z@6zw8j~&h5^jmKALxr+(4QJ9b;0bY}dXum8OIF_?nP%DidxK~XY6sjZe<3`GD38A$ zpD#BgN#tLuHXkNwlChV+QnzW89|~V>%{pGy4ltR=_*5z8{aXrT5Z<0VQ{F!@5iJsM zyCxX8r50uU_bTvtLFWC1`(FaNdZu;5;=K=arrB?6Kd}|RG&#!z5;D61r&^TU($md< z$^J;t7~P#amw^g$T&__2IO@ABCDqsMmfXZp4`br65f z|5U6`S1gdZdUL+%CPpl9+w>mg-|I>P%^QO5-ki^ciZ@iu+!02kLE>3Q=fm{19j@-R zaC^$t(Q>q3Q9hG;eWb49C`BYT8u8!SZbpEBSGg669@z$#OeX{3aHV|5HWk~P3?dQAOpAnsHC>}6Q>2^QD074R zXG6HVz4}GmoQ^&fRGbT%X1v5@o2bl| zAdo(i%?kF4%SGLnq{nDRx0w8a`@Y#ZO|R8m7_|4Yv&0dh6FoVm8Jx4}YjL0jBuLm5 zV2$J?{r!4 zw%w9Pc72V=vp1F)o2xcgMF1q#OwbN5I_@l8cq|<;?MwJJaQ~P*uaLrpz+tr*v(^(P z0m?j?fN+&;rM`E?dVY6gits1KcA+t`CxSS;b7-b;L5LrOBW7wy2G7JpSY$ji+Arf9 zyRR5rU#bYq(&*RaXs_>IjhiCec=l?SI$F<+b|V-wlzGIp2?-Y|Ripe2CkzAvSE&}) z&$%ESza7Mc1N6^az?W31u^8J~@p)kXD5USYS&tG?TJ?Fss3%xTr`|3Ty$iNjQhWMX zr^yU!b-vD4r=XJ<%krVI7Lm^2n=6%EQYZ>rCNYmQ3BTw4PPJ=K5PI}8$`MF=Qt3W$u1j(3-?)ieWojA^*NBNxXID^z?)}3BdCh zw3;KIxuPsa-5I!S+hf=E*_MEN$8I`rGxg=im^Q!tu=@LtOK&V@ynRGz)b`jvpYIsr zv1btTyIrbMe#4^U6qZ3q0R{^x;HpqIo@=)I@Vl8bbSYC5w&*T$IhHQoaz7zz&-prt zh23_Kg6Go)vqF;Q5xMmYSjO@f%hKaZOi*ax9|p?sLN_fS?|;+PNxRrh1@#bzR27Y3BW2bb2D_$z|_(iX3`A@z#8h2*aON z^8%9^jj}!qMTu=7tbr(u+G;iR6#384gU(AR@dsOQ!BiO`x%O>5+!6}V*?k?;d!fl$mdchdRJHT zu|pT&P8s8u1Ga{egh4Qw0mPch$#q_&g@PS}xnI&Bfgnk(rxj8zjVsOdd_Q}DRj*j7 z6a%oozq(!=_WE-*YDWVt)DewgR`+C$JrvNWaMx~McD_aTZQL5v7@hP|D^kw})&64Z z3w-vxH%eKG53aR8K#;he$M8mcKy^>M>z&;0o%0FTuiMEwIVAC*%znG+oJ_K1{BFkqv|yGCH42JuwS2~<7i8RJ`C^0?)*I4E<&}(H9g;-ikDC2$@~cEbI`A8 z(407P00g37G!0`c9Xn_L_k0pQB(zCfTmE5+MRnr2#;sl4IM4p?VP$$P(ieZGa{wh@ zX}xDy?eR371T6vH;6Z|Z$>$prnj~q2&$qITzqf8TaMI%+*)?~aFh&e5>yaIb3c=@u z%!-Icvs)_X+WJkyCKaVLoX!pp2hJ3`4Ey0j-E$Pr)s|>Cq;MF0QS)TBmFr1jhi6X) zlWmmd2b14^810J^Ei}l~zp$+_J)_E9a(UcO+)eo{>{)-~$7`4+COydhxsSxL5N%n| z^i-_Tbu)N;LrBN0@UXAibt-sZ5*x|-X)vjvTS@?R3o>l6HzNH_iUybIr@1!$5A)3~ z*-KTSwr;1_mE(3J2`p+F%Ue#5&D=$g?JPQ%1T_!owlyD?i9`edXTrQcDYf%h+wPrI zBy(m`ViKQ=?|6-{pJr-5*}P>l?C|E-3+vtULX{ZqvtP7GkwugM)mpmM33KKgM;AIi zuy+r(Y~!7_?138G8APnd*ssWhvZ%y-8PO$$di72mo5$q3Fi2Q=t0nd=z;|mU({<~( zv(f=2+pb@Ha~J!# z&Z>XqO;GK~sA|&8!D((t$|kjRBnjyQ(^7==T}Zq$0HehwUY;0B#8UM>Kj*Kv0`4Ev zIc;^zYa#)P=B=T%O~^hHB!uvbB#CCG498dhdi8(9ue?9(Shjr*#Nd3MR80>11-rMj zt0s?V`w-Y=(V#n|QmMkoh|1V+SulwiNSH_WgfS@POKNOx=WDHJW@S&^a)-Mc09a{9 z2D^T2?p2j-)8%BY1DyC_UCXlaMl{nSHHLohi; zz!f#wY-&wKvO2r*i4t6>OcaTZX=44bo=)f{-h?knJgwT-U~D=&X9TA1+`wB>VM zkm5+bVHmW;Nl`$q2^CwFq*F%gc%=WHFUprUE@Zq-vJXLkVECYAeSf?P6-+EB@N+wZ zU&=Y_MMq{$#&3}9Ob0&JfvLAjTZLnDy0>qVi+m%=B~@?FaS>)n>Tdg{ITr7(zn#oE z54BqAaWRm=LnA^~PK9J0y$f$qM;3lL#aG2BId$y zmq*#Ay30#VP6;Dg^Zi|(VJ>G_8PhgANDNw3(~2AxlikY7x8@7#7xDfa`NOkc7**e( zCUsL~)eW$Iz~4iXqwdDN2adNv3b!;?$@HluG7jj}Q`LO~;G+_rQw$unt{ zGz@)?H&wZ^8}FCBKV^o!BcVF@Qt&5hLUSJ0jDOX<5XQ7i_lnWF)G*i;7=ep4^1rs) zI5d4&)*DD~dvQ1Mj@%+$*q_b(F|y+glsUF3V&ByEa&!RU1Fk@&t&lVu z>;O|<<=dNr!mPLn2Y; zT9+=9RB1rVlP&mIa<1i>X2>6_MJ0)pb6hSyt9jwjF&_<|=3Cd9gT4V}0%=rCZ@ds$ zXV^tG>HS1fcdUZ&@`=!>`WIlEqYnj>7Ea{kj=Xn$t$ck*#w>4gsWB8aF=LMEh3lx!Cp6`7s258=?B83WGT9T8{ZQUY_fnc!(U>cLBGLC! z6foAS2TCo)0o6i;XbR>;SThj+s2+fNhdx7osX&#ZoSM)hCiG&^i!^@Ot)PFRW`BC< zW4m5nJ&I$HqvjwbVAE?#!i)(2Fvzx9YD`26h4s`v-t5AQl8Gxds%|Bx)h?Dt(r-bO zodwYj&@8J?f?XH8G^=o``(C?*d*wpJleMQRVx z*bWA9KpPAs03mAa_yt#Ppa0kZS0f-2ic?BI%2#jEE9Mmkaal_N)^28vd`NtmQQL?{ ziIUs9rF-AoS=zx_P6L;t--NBd>TTp zPZp}Y#d>)4=sA%uuk0BuSyIkn{aYHQPnbwk1PXdUP53zbkpFhnovJ8PBp}a$AQmUd z8h*&L$pI}L1}UD#{Y&M$*TztgVOHCWOR-YtkiTajQ%a^(^6fu289wmfF0vQt(N)UD@XP8@MO5V!ppc zkhxi1$4CzUQkH-aePg{}>3!{T7Wvhz43wZSy?VLao6_9CHX_I;Z_QbZYg?ndUS%O- z9n(zPsM#^xyoN0!B*C*9u6OU#KMAA@%n?loq22m^3(swZFszw`mD%KWMG^2vlX-xn z{*Z8(qz`450AHahv4Qpa!v870{)TFknF5#PSLS|COi$lf5f&f8D#z%Jl!03jV+c z`P!kd=6T~`huWuqsx<#;g(Ly6WoXuJ$3k|=|HHv`_3R?%{~`S^f7n0OlE1$Ba{<%i z*B^|ru>Xexb%p5JDhj93ulE1{Rv)xLU@JqL$sH&8Ck_42Z;O7@y_NrJO+vYDY!Dh|JG7hqp;&m-??y@bM+MCE=^*T19Hs zoa1>6ycX+Q2Q?p05ceh<@WH^Q-RjRij$|5#&FmkKE7}Jb+i$wV?)VvWDyiCUpz~jT zeMu+|eBKqBo0o(<6Gyp&+Raqd|K-p1iSz|m_~P8;Kzph{(PvRLu)bWcg)9<2Dl$aq zr{Lgt_`!mR9aOIAf8NjMOCSVyZ62a8Y7p#CnJ{PD%C|2QRZmOis#JRA-(zJiR#+zU z;E=zQ-J2^WX3%d42OmZX?2c;NnYC7PMWyq-UQnNqg2`GP1;^#JT)INwway!S&S~#q5XW~aF)jM5 zrc_H^874UP!C-~dEe1{L>TUXsI!`_7oST#Ub9TGVSNlmhmep~pmC9I-DFPnvM3OUF z_UBu0#KZ8^QYBjKODKVfgWa}=z;Wl`pmcy2nG4b)v(id+Y zB6f?{z^R~p(3Rpi8o65Y>B3dbX@}Wx(&d48AeqOb&Wif<8OYqInr{acK*vnPYLg?+ z_}`QS5>2qgStA>1)c0qfA-J*0`R1Afsno=Tf}WwYk6Pg(EZnbp}fUArFtNr~H#zqkoW*&F7nPTh!*2aQ2 z$-h_tJK(P;^A7Z}2QR;n6Tf0o`u-b?4a9nSBU-A>nXO&>2V)QAB%C1ebdydJ1R!|= zElq5OCGYybQ)>Jb3I}5|$P@C`_F5)w+I1RLT0w47f@_+jQw4HYu#ZoK))UVP!GcS3aRHB zw1>l8&TU{Y-1CW2XJe+kR9#LZSVQ+Et$8xjLkGb888?Swbp6zH3%wf412=2p#JIP>DpqiJF_A5X_Y2Vke;+Y) zty{hPWQ8!HxU;Y)DF6@TFN1050OYAO!$>H1)ffI(E%$%k4>W@3x7&z`G(r0D9_Eey zqwjfddThaxKB48@_|LpWU~>>F)+o&gL?u!LO*tCG=nkNx9tGk!i>}*RSzmdjts%jQ zO&Oep9d6d5~T)|!1Ux&8vT7h;`gh2styCJFHr>| z!8}l2V%{B+H@t^ze*M=|8!{W8t5;BPeZ1#>t_S`(OTeI(HPi;SCJl0 z$Uope9WS)iADy13kS-F>sF#C3Q$Deu$d)kUl5jY|TW}XQoSYDZt(ebhkAJk-n%l?5 z9&ncs`cQ34$8U1V_4N;!;z350@??4cSzt>ihU4#13!E)pPrvV3>$h>`l6j<7E8XWX zVj1OBK!05hS@k(+tUSHwM&T z1X{4zND7NuES!jYz}d9(E2B<6kQb``KG3PRfL)JcoAH9iye0rb(=YpkwY`ShF{W$JJ zp9Wz1sebAx^Rm}0mq#-?mNX!q7r((2aWG>9WPVdfb_L7hp>j%@xX$~SHsgfWGOZRc zYU(R+UlD-IelAv(G29#ToEva1|0Sl~9czva4xMqNx>RlYW=#yrqlQ zuprK4;EZ?E)hEaPVK;Qt{^(H?TAKmp{4uwwh5z@tXAtI{P~quw*!1}XQrzsRfq>h? zgV3-Hu}va@MFfSAM~H@-3rTXqmh-CHB@*WvLVNt2kjGi*X4i5;0XlSdF*i_@0b%gb z*F52eFP{h|9I=e8t0kQuxde*R&8Zj0J$vQ>y-t~L=|+wHI#1F2dVy4K5A8%3vJ-$W zQB%ab77_7MhvcvTO?S8sC4xNn!QPS%td1=*BVqIev&85i1)3PzB$ z`%kfGX~W2w-+j!0@=TJ>nfu{Mc*nk#3*4(?L`W3pb^5*3= zX{K}AO3AOt714)M7!cTh?T$Z~?0!%A2hs5F7sQtUGRx;4^1W{c2jP5uwtQ-%QuS8p zD`7kV8?^Uro^r8|!G3M+y5~>(sW9HJdNIBtU9I5p34K)XZEB;?l=OxDa<#&U4yMn5 zKl~jC(C~+sw@1ctb1h3ctC#+Fe_BjSa&MFS52jTeFMw)~zL#mLxfc|t7p71guJUA) zNV;OK&^F1$!|5%4VI_j{i}cP}vb@3B&WR{T{z)_4l*!0`;`h@KRoCG`P-~$<-O)8= z_ee0dSm?V2mL=b`+wo%aw}ZJ3(np}kJqY55*qO6Zl9+1az&hX2-}rCKkeW-u^22fF z-5$9(aH(ZCG2h;a>Y}Yw(6XFw&P_|d?)~tfHoIfXODT@ckirC<%W$#1pz8jx^?CWxlE9dL@e z`F_=!S8GI+)eY~g9}ULEZx1AU0MuyHjLUauN$>yp^2P8`9LpBJW45P%V`-K>m|=~d z>u8kTP0tzcJ4MRsa%+AX^P0tY01C^~GVN*mCH&S0V1#`C%jdKD^d-;MnV~=yf7gI6 zcH(<5hLlQB^?F1@%bAbm3ger*4NPOE$CsXHeHWxQCLMV&d8v@EWz128P-Cx4^tJqj z`H))8)X!LB`Ve1J-F*bUT2Ldo;0PSo#U2bS=xF57bMQEfeu3al;4@3RNQj$4Lm>nS zzS4<&KpC@dY2lI(G5xm%l%3d1Lu9V$M(QVaqA`-Hibf;)#K3RIY9_)LVg@$cY(!w3 zdbX$)4nvB0J^gvDIiCpe&eoyx(7I43zQ&(6^*LR^9%r$(@K6a|KT?}yZ@BGY$fM%o z+oV7C>CloZ69A$S@o9UcG>h!}5BAjdR|G^jqz>i`!xba-%Yi7uIV7Q)#07v(@y6BC#^;q*~Q+>jNui?F4fPD zMf;^{Hzub0E6i&e_*-AREMMQ3`2|JLdakPn>XvW8wHvYGFi*uk9M4V7N0Nv0<7xddwq z{z$e_SE2F^-e0I!xV<3GXa)S(bELTpR;oQ=NQ#w|7s!&^p_-j?kPx;*AY4={-`>ef zqL+WZFrRlB9)Tzr+5u=>Y!a z`+LgUz46*)?fEyYp}1`Glr6wRb?_ky3z(^6o;G9bJ{-)~#nv6nYgZPiHPsCzw+T5N%~5Cf zhE^iNiCb(}tah0KV|kTFue|M!AyETq2uLg3Y45H+47^#Y^T z0)vDl={B)!7jwR)@kU6)XW!SVP|wx4gy3~Slxje33UlNXpMD3evRSSg8?Q25tv?3b znNAgthecD?IR+iRTN7~)A6jqT{Vpg(4n(;zVd#Z9N6mIRXuPPhpD?qWDypSitb6kI z8E^G~lkwO$8BS8;v{}rF8wf7^Wjt4cfJsf8=Vl6q-G8SX43wP(2Du4Y^tf*)Qzcq5 zi&OXwkXwaf4%Ox!lCbsm>#$Nq(<*hy!llZ!MgHomrEL$Kih6~XSR>Ge&0BW}N4Z*v zSd8@R)UuPmx`LvzDS%fnZm@p}ZybLrfth+JvK(s}i%tVK(AOMRZ=FUZ-%{X*cLCYr z(FH!|0I)&iDlE6gaWcaggMf$@$rVBde~}adbiHcTZjvV~)NA=Vl)&g2`Q7>3F5F8-K5R->6~SpR&V!73+mg-Z%jd*Y~-i zz2T?BZyR!Cw&j(x-#KEX-Ke`>?OI!+tTrgAL9*z~)j1ZM3?)c0RBue6l;J3TC4boj znrpMzGri2-&(37WUIgcT*vHEz)|_Z5aBVsI%L2+(sx+~y%>j&UGA`Y%caLtVVLIuG zPcb*kPa8+T>peGewA+yQaC;RmH;_@H--S)k_?NJ+yVxqO4 zs**q4LspNT@({_h7Y%;JK&uHk;LZp(*zq6sn7eb?fz4_!--F}*kM`29%&xCGMLttU zUiUO^Sc7JA$$iU3f_&r&ya)){dW_v_XS%~OUkokFXY(9mPKMe^^jlnG*)7-3Fkbwg zXm&X(yvXL24A~l{P%D}ouhDXlX@i>#i6r0_d|ecW^w+~OL2!3gyXi-Xf+B~&AOT-K z8R7=hLy7b2{uC7NW8d2TI$W~4$!e$qKI76iFLQ4%@GZ#AQnj%W#w21I$qo< z5C2&xJtyEY@a8lMGqGXIQ<%}?-3hG<-vG1AJ_(f?1H=Gs3lYmeEY16O42d;8tgs7> z_G;fVz3d*1xl@7Zo4;r6XRvnFcB}J=@|7UamCjWd`h7keSNp}VRA-ya$t6?35%_fd z@CBH6TrW%pHu_nur)53dbp!Uz)DdiG3tW=2B_hVR4Ge1SrUr~^)^eI$|9t)Z6wRVS zRj5<{JioGIr<2lI38&~LS2G#+TZnEHXjgmwNFPv4E#eEXSEE{8pdF+L9i$Aw?)OJn zcT@rG{ivLQ(K5Z#M#SiYLtxS#O5v`as?v6#-&85!$OZ$C%3l+VZXYiiexns#Dg3&+ zyZ?y4*+2<_0sjbXAq4y6)`$MQhk?U}4N|g*)%?;%tHkqodmvUuI)1)o>%18Y4&9i~*F z$yz8&8N7-chi=)JgJ~pEL#VN|g%v|4R%s?q9lGML>%OvBpMPlj$;a*Ag@SjUkK#9! ze;z2jCOLZaZM~Nvej;Bcze^~Y7|8|jj zke~hGT#*XFf1752Krf0mZ7r|+8Q7!g*3mZ?rxq-D$F|c4nKvm@xD0*w=Nl%tN?Wo3 z!Y78aR7YzBEVL4wuqu$nkE^Y9pRkaulIk&gwW_g!P+gUYkX9?z!Rh1f8f7sVCOJNj43nZ&)o=F$K{Ns$ml8!Uz*D)yb_g2L0e=*V4OF;Vf!GK2j!q2)G@nC;( zS7WyTU6 zwRS7{>D`SRz(q`2KN`6`+;ZUZI)(nEgEawe!dhTX$$Hl#V%^rd|Imj&@vnP^}*ZKzW=O8n3J4#^fug)p&f54Qy;TAE=H5zv92-{kK$<=g?uVf~_z zOdO00A>Cd4--E#ROuJs0pm#T}wI$E&lRpxvLangdkdZABR^>lv6ejMkfG1^fS^QC^ zq$8PHLC;hYyUzJ0V;NLeK0kpLFB832W1TJ40uDCIR~0JJ2D30ejmtI48y_}>9KNf4TMK2_2w ztKlJel?B-#rHDvVK@LN&+7GHN?9Q_vR#Vck4^`C$D0nY(_BgEi`joO^V0TKB>tj|i zh22V-ONJ7wB^ypR8T2?60udFAS!0*5zG*~;!pbOsluZne(;@@8F5il16V!d6wM2chjRpR%;EJ0)aRx!tEJ3j!> zKpf;XsK!whmY4*Th3E7RPO9_pxQ8(9CL23u4vJSW~|hyJo+qxb+Ei z>RS=^HQ_#HT!UgF-HOI$P@dhJ01li7NQmtv4kF~1N_F#tc}GV`5kSIY#M2#yIVj&x>G`A(~X35 zw{(MaNq2WQ(wvFUZ4V5dNAaczs}er44E z#!PyDm&;z1z5Jct)b~x>Qd}ILpwakHl{$AI!$7B!e9yg)fvehw;HtATny0M|HYc+T z?6u>zFN6{c#|O!ElLn2 zi`h=sZZF~c+2j=m{JB(9|h1vDSW@ zQejAQ_mDfA13yVFliXVC}ZT29Q7&_{U$1Z~u7vsn|~;=(p!cQib-p z0Flav8ZMgT;u%Dd=|PxEN76S$^m!8K$OnoPdWaemmdv~&OurWKUec!+q&aaMnms>; z)V*%SJi~moadf!ESDPt_o$O2+E~npVzsP7q=ZAm1JVNl)|Eu=kEkfoN(rBTBG3vuh=CnQQ zjvMGp;1n#LBSjQ;BtdF!xR~JB-@<~c&RYtYE3DWJvhI&Iu^M;u32rZaY2;Rd_$)d- z07rwOYKu_gTuvJO z0PCSMNxfh+k?8(M!@PR~_V>Tnu(UTagKLrp9EgR^Pf%(`z)AovwGP(Uf_+Ceua*mdc+jNWxsat;&R{#;P=ywkfF0tGP57Tzc&9&8PcszPKKADkt+uIC;;W3h zu1J-+^v~N_rn(Gs(M%mhViPbP5>unlgMm=4zUwwfTX^Uz_cP$mAJp+Z*LIjm>1!kAk z4Lu(BwBPS^3mD)o9AVU^5Fp=QxL9y~S(^_!X8B%`Xk+$~NPFBUQE1?J5CrGsC|gok z-(jL#EQ<|`?fpHKrYGQFyu}Md_g{831;cP&4~7#*Ph6J@>TH8A;>jl2U-0k+i7XSf>b#x*>GeDO@LxB40oUunE0W}L8cN`R zw7hzGlY({Why48Ccb4Sg06gsHhZlAB51kY#>W%R(^0 z_^H#O1kW$FV>zUaM~VM$pF_LFW z7w?NX*HDR&>cXmm6NpA-Ic~R$8_a07IzFy7Vmn`pkf^0FK#rEVcOc6CcMAOP{PYSH zZ8C#fsfE{FZIhm_>KkDqFb`^HSB==JfF3U*Egu~iI=%UxJAK1fd0=xUnvGpFTiEmT z-=~L)j^Nnm>8eN-SQm)i{4x_Qa|gARN$9O3t~OokAQMqvP|61!Lr6ncbgwmDyWtAf zD?2A+VM^Oi!Hd|$-$&Me&!#^sz~5I-{YP40Qeh1&R4H>Q>s;fulOqZn!+k^6Wb-Y; zYbTF?jUQ!SQ<~r%%u4c-qe}4Ki-J4)!Iy^toPL%p6lZ1n(}4#B0t8I)XrzmVK?@Ts(u4!4td`o#BSBNbx{>pY%yjXnZtMQRcN4|Bb{-&ZW2-z7PS2SBD#oPPMh}VBjcMY-yOqe67OCbh3 zi{~r?$}ru>?@s~?YHL#a^Cv;)mWtg+X?j<(`$F&q(C|vt&jWLwNYDpBhSy1_g3cy#1FjFq-Zm4&0)3iDL z5llFp;ZUS?)Un@KtJaog4U+I-QeP`Y0VxlXyPu5?&0=0|?;41r>zU(rIZ?qID`EsD zZ}^AFvYw@k9tzNdEI8K#eO;fn741WwVvz+~(%x*1cx9pH3X~=DZ-DjhZAR6AckJ+# zL~UI?B#+3gUFvic;)<0p>CLjun60$fF#TTXI7kLeq##g?*UVv9-WUC{mO?CE0gF+K zVt=l_tY)ph8N~1mXC|1tJ2`gWm6OP0C3TR!{UQ#S^ckj6-OluM%7vlsZdamlav1;> z(ZK@Xz^J(G)gE{5fK?w}=XUkFbB2-jzZabT`%ys`FY9;(`RT`X>6l>CFn1V@ic+=P z)2b89)q{iQoxg22-pz#*PFG5Z8NvdN`=s*leGqFMi$O)F8qRVx!RdHqA|S$gZN@2% z%cB7td)#_<4tY&&Z?0C_bmY8ki>1!q0~wG02{K_cVXeK`6*3_OH1VUFr1}8%@S{&Bl5e_-5GM1KNjLE(CTga{lG5&abk(a_D=#-v2U z`O>pImJIQju^KArB#rpjW>k6O`BCH@!99RlK_N@Fjk@*t8Mat*gBv9<>YVf8vo!1N z6Gw72r*oy2Ni64FS>AV|ayp(D?{IyT@k7L?LO`crVo~Rl?sY z9Q_kON2XK+!l%pkznvCjL5f4)CDwM1?ef@oyhO?+yd$cuHop(Y|L@Av)N#LV&@2)R zAbnSyV7lBXIDJpw@lX(b^_qofuyD|CFwwIlSpel#}si<71@J6+694^gTyO>)TxNcyD8vxJZp4CMo_x&@l=aoZ8;7XlOX*mHf zXAX1_2xPDU$y_(64^P=zZ&azN*6QAD?Fk!BvP2AH%=N|bHcRj=^O}31dhM7jnz;&< za*~?kGUCPMSId*@PK|2o9uR(CEoNDwRmjhV?q7s6=?bL98lfy>z*z&Do#Apjk~K(i zyYU(gBpMq|P>aU$@!Ua5t`FBqoUYGHnm%2FW?&LUb8fa|_!4QR>t8jh4M0`lWkYY` zE0Ky1bNThzpq=VZ-5%jdrmZ=s9Nfpev4WM7qjY5A*9r_8RV11<_EEa6A{%;7P>2+I z=Zvx4FXWE7KrFlg>y?qDn`O{h@oD=+->wbFTKpry!xQbf9i7C*P5NQD4RnROL|p#K z^dP7Zn*K(#R3BO5ltMjkFtez@pEMKrqtVpeI5gTR-mgWW_Qx;wRW%F=kd?LQ1eZFb zN#JKcOx9JC&||Vl;L&cO+$XL#P5efNW0B$F?1!Y zBpu0rzSD_DZoqfveu;O>X@8QP6ca0DC^%c9@87E+yaQrm-;FIcP*+c1;o7wNA;lal zwstw(T_w*{SqWA$>zy;HrqwyXOZUaFhqR*h=F|4PSOJfV^L95clPR@S5}ESo%%B|Q z7j+d%sc6YD8W@X_*b+G{+;yX_>@{;G8KQZRu-hJHT3C4O^RU+VmxaWjUR$7q@6oEk zU4z@@%mTkh_hMSd$;~HSqyT{DgC;Y{GEYz|(kaWDHw>*C_r@|vjJWpo=k6-KRNJrt zWfy4QCjo%UE5$^#_G~x9qW*G9|LLb|5L0;*!7za=|Env^(Pk(3a>eN%i#~8hVmy^0 zp(#XHIAVLW`b7|^C=S%`+z^77B%&@jl5J+Wom0pJ3wnyuJXUy5i@t>;SE1o#?ntj* zGr~a$nnhw!gfN2y74SaeAa0jJhKrJxH0vLpsLGWYbmc-DHnEn`>=twhvewY!S4Z=d zhk!#3LSf^U^VJ1`8S;w>?g)rKHL7jsX0z0wB9R{F2PsFX@5XE(eJRBi=FRe7oKgX$ zv$B5W04Jqdh3GL{QQT-$PmJNv4+M~4nPY}z36t9>2y3)D{-|E<=6YHp1#b&dNP&l+ zw?UVRPypXojS{>&KqNB>(}kqcLoIMVt%d6QP$cuXO?5j8O{UPEu<2jgV(q``uO^!# zsHM9pL;S}|@&KVqpoxyC^JgV-*Vp%ZeV-8X1QZBy-TkQ1VOaL3kx|Y0pg)zTx6gu8 z^0HU}zjnWI96?scHcBa}`K2kt49LqD#QXAp`lyTp6^o#Zilk|jnX5mz)K~l& z^66yr6}$kobn;Q6!g}xIs|M554_@AnPpPH0Sf@5V=|16~2Ny^Z`hUPl>Fli$=bX4U%^@ zla`KrsZsSgLu0L%XW1M3z92gKc%mzYF`38j;j?94o6O!)ao@YCZVAlXtpG4jk~Ui3 z{Fhaw6Y_hW6sh1#pS^kAU+=iD$vWoE+COcf%W-K4Nv#|7tM`Fa?BaIpZJ3TQSE$4< z0SWxktOJj36u>C|Bx1EWB8W7fFGY7@yIb3}uH^$F|;N?;{n1vW%WlI^}#GP>VHwe6et0 zOA!n6l>c)Md9!0Ur9`2ih%A+Mo?O^teNF~^V^2YEjoa4w)!X=<6OgkKgpQZExPgqHZ|m6 zv_xD{-M_GrCgKJJnWqyX%My18B4dBZQ|&Klt>U|weG4DGE1nb3S7U1 zWrUNxVP*fH%Uq=2Sy)3^k;1TmprS1P^}!*xQ`TdlobTr2?~sWgBj}I*e*Am z5DaRmu^K{|3$|X)*WT$Z3f(Us-Cj+tx{d1wU-+Qao68c7lZ~LAvH1bm12!DG}a;Dy%eIy4o$SaGE(u zA4PkUjl@f@zbKjnaUv6~lF$CAyP4{aI`On!8zjkZJ|VP|uXKjBI?qv{kHkI}K4)ya zCIhQAmZMNTrGE&)pr6I4>8PvSLq?WpO6HX&FPNjzaqVZfeDRNQ^-CZkQ{QZABA4E%`#31z^{FW#iswae+Xo2f z)AOZWU#3osI443Gv9q|NNId&4sVW~2;wPL+px=e8OxJq+-r)UP{5?nF6mr`eoQtdd z##PYL&YSH{2bDpANUV&+_IZ!fh|-)04z`MZiBW+Xi>kZhkA6rVj<%XBF# z*#oP$F@eP{o-t(UU6d}SWnRs%otz+!Uj3b)hsrt1jb23zC7G1BKiL%~CGLJTT9&h8 z`l^+G$cbr;EhvTFYE+lL%NJNw$3%&xqZlb?=1YK@~A zMH*0!UDDg8cbai2(1$H#O)9uxw=+~7@tj^kv^^;Kn_Uh_KldsGSTD7O6qQZj8P=Eh zT1{ohQ}431p%WS^oT*auG{=Vm47##MF@|c*&2h;5s->N_NC;t8kO{?v$wYR^$u=*a zjn^TP*I)>xO!4<;dyTp(YIx3#7!&%Hqrbi1hY}AwV5o97p7i2}6y478W95|tPvWLn zi%DSbbuQ-_ypyl({-EHUlsSMe_AAsYNHOwJK()PNf&hL$9Oem1Pu<0{6|+;a-mrz$ zm7*=nrAs7y!|jS)XKqdMFx<6aeJAo|98kCyqwRimgE9$}0lf?B8hQ}Xf`)yrH|5I84{66XG&~hKs9pj zz(;kTa{+BvZ2YC}o0j+v73-&O-U0Blhb7Lbd8MCL=WVc+exfnFR*irM)NVPmZwM&F zwNu*98QMWR%)xGXBcs)B8-KQ-l7=JTTvH1AAufqx?=HIBA?gS1q|ny70HtI3I*Me< zS5>{XFBvh!t;cZO#qUm7PW9$GcPtnJ-5Qf*H5}~cWvPOm>c4%Top$vlX7(79PNSnf zAd9RYkza+Tz1Z{=uMdCVn<^qhy9afZA7$;q{5SH$?dlE*D#^r_$eeGq746F#vOEKZ zGNUohPQt+RrcgkryoglCBefmxP=yXEIm6!H)9yreR;^U z@Y02X{DP6o48M1|pLi1_MzCGgF^2{Papmu>k3$$+2Pz784*|$N-7Zh*G7!b1Q)i>j z{a9_P+&nE1FC_=`-iVxHGt1@OqB)5{ZFnJ`L&4J*fBqvCe^q7^2%Cq>L>$WB89u82 zA!34Q55q5NJUdms(sqnJ#ngh$|IAQbuOLFM;1SE8GDY>D z4FsMks)MM1aW_?9g^^@(p&ftrZmiX^Z6nA0H?8^yPM_G^E?GALWiMTh_h_bh258guRn0OA)_(OduS`w z)4NgwKTmlZg*eLn=5pK4qJXxZ*Yn|cx|n=D-2MRX%?n2-4%-QM?RH;TY(~t*-Scw& zCnke+ap`ga!|}N>CZSBGJRG*nsjA=11lc;=|D(h}#!>Zqu7EIGllQZM&1_7xEK|x> z=pD>yqE2uobGP1C&H4|!p?-e(NY8v%1XZr&;!XLW&w->!IGfpPZsB7V&Hg=XoF%Rs-|nM1xy@p|3l_{r zQ~ax{=lvG!ep*2zthm>r9oDk#DiJxWMK!tmEUpfVT$LABl-WN~wcaZO*>16rV&W8= zo&70LsHi5vC@0lwyXVmSx~w$MJ(+UCG^1?zZ>=rsul>+5_3mErV|CQ+YY=baDH1m#nb)sBWwl z*BmC3snrW@58QiF%tfEEAw6OI>Yw+S&PO}ug_b~Ho}`&VQ>*mKfB4Gw4`MC*P@@y~VjyKTkR;&tW3-20yB=T> zP0FCXGoyopnLh4xH{)t>-P+CP-prrNU)HCK7{#XHam2t=tuJpVtcpXjNP{?z$!WWv zGsln_KIJa#FqM*0Z+7h#@4os>j3Vq-^V5kp1uUnHp@U&gxf7>rLs6pD7e^ zms~;bk$O|uZ{Jm=9s);Y1Z6j@=Ea(b?wiM@irSTBK11D@bSvMUHnJB6;l5Hc9WTh^ zW{Rz}pgZu>yL>EgM#@wOr9r7Mw1Q@YK{FzgaK-Mq7p7w2jybpJLKJ6YlS@s-`OwmEMOn z?z$tx)w_#*bda>kyYMq(bUvK#y_zVJ>#^0XHz@0s9pvywAsos=rxJfJ_RW|@dEX{qGcD+|*48e)&z3;ztCkO7S! z`GKpcCe)diTDuu!X-x$5R@$M@;Trvm-EExNDk}^EmZIlLrAMrd)1qW|MX#NO6K5UL z`hd>k{TRo)baxxv05n~SB}x(fQ@xdM@!QY%JI^xv)K5$G0P-O^cQjXGx}rew?51zO zD0wvLLIz!&xb`Z9Zs11hbQ)Fu{UbFUf;9zVkz-sF2;2!F!pv=*5uYEYgM5oQ7hTa) z*Ud3_U7;ly6bj(XfAK4Me|3w{PPrysgHd7n0%rD`K3})_sUgTnARsauKWcpfmzU?w z=sTV2+`I!r?Q z{0%~@ohg+EVGyKG39Yr?ExnTKDI)4mzAKhQcfZzG^K~-Uv(e1&dnSzxt&XITHs!?6)&fI8Fnhm6@Vo_DB9>p5FL?(`}C7@c5V3bKnvUR?rHFmyj3vHL}} zG{xbRgsUYoGI1Zo}OqK^Zc+$q?+j}tJ>msU**Y-6bPQd^6{s>nu^4hPcN_O3h_)`<{_K;`lAu! ze3{@OR8!P$9m7~g6L*7J5TSg*6#El`<3n@IO%8-WYs zEyDuUZh^q5-DE>F!^?00bb9=O#h4t&;TeDvXpdCz~>NjliP!*UIW z$`;3ez$dNY?_($>@@rHlAg0kMNhbiC4NbuS>(=HKwW!e7{)snBCJ7E_GvqYMXii2@ zQj!YzM7FxS&cdf@XadX3BpXladFs}@e#o>YG?1dL?MGloK^)5QbqnwkS!izrzhT&> z{S89%$&fI)PB8HgJ*SvpS{rI@4WoBr33OJ`-qVM*sTR)pIDTmA&Iud99U9wlO+Gin zQ`nrw0-$s^{H3TA&zsfS_u!{^K_7J@!1JB9RlHX5OEDhM5xxLDmb)^g@C)jqW5pLc zQGL9=6ze#09`Xwi_nHwDWeO(9xsg8~)Znd&fA=U!<;`PVr^99HP=UwC>H-|hN+KE> zxK~km$^`x6whDJ6IT5sn@09X-V)GDC3iHq)S?`jDZ19*pelkIu9=qynEVwr)CcXFh zLIyjGN+JIyl_jk8{BVE0f1`C0>sX_t4tq^X@6A)#0eHmsB1_}1wsso0Oour_I>{V& z7yJCOMo^bIk1j0N3os=TJ~>!_b-sAylzofuN1;3?2{A(zxg)H-oY8jnOM{Fet^-OQV&T8Jxb?XN2dG_D~}}#R&m*A-IgChGhJx0=}A2<)*HkGis`{#yB*hw?hDduUhI@k|)*4T&~1| z_zsFG%(BK-VKS^_%>7sd=X0J?fr8lln{8+#hkxiA=n1;bq-wh|KaiN$E$D#b);SU^ zS%68a5DE+!laQRW*MBCuh&kRm8hUVbvFNQ20qXfath2fDqzXokzQ%l=Nrdfnd4#(? zD(!XN6bk-p=%CMx(&X$RKb$K>8$Rr;Cvd;pCRxxhv+WpD_t+k<@v=DV5%^2#T1*?1=XdR!s)pV?LC!@TcA7e_en;6=LM^YLic=~2(c6&M zJzGKSbX*Bv@<8pi#fXfPd-xWmn0;=>8=VK=O;`2vlR0hFsJHnu4?&x^ja3>Q4vrJ+kGJD@Bwgi^de(f4vf`@JYtG542h#Q4$6#a-gm;F zl@kr%WJNn{dH8)d8&~Rk_>QheDSxD$ilvYX-FSd|?YaIWn&Uc*JR&*zG4G}mVlNk( zqnrO1qL)+tSu=sob+ifZlFnZ2w-F_<6IOTVmDhFpGr_L2sQ|a>UJW8oh00~2AyLu& z?ae!%w(5Ao;V5REYE+y|m6k3{FJ+V)-ZPzDJ)5hF<&C^(f@V$wp;L+CJtC-}%VJ^0 zDN{1q9G3{f;zz;&pB*PTS;owx?=9z7ILm`S5w>YT-iWU|$If%s93@Gv*XC7=OwjAu zNwSBC?LHT=XRrZwI-wIiSb;|szk0OrZ{7MUq#bvoi&Q8vyJN~J-jz%C zcj*49?;=)C@@XmNE!Xo#b-{U7q8p z%E1Jjr}3@xZg=%sUma`JE?eW8nylJDlKJOw*x`GPN@K_p9z?0r!eW50$=*Mcyp%Y zX@zN*{YkPA?BKoHwAX#>&F}*$X~rV{`uiXtD{`sSa zYhJ9vzi74boW{!Y>jF2*P)n`m)TdgVC5e*H^bmc4yxrK zNvmM6B^QADpEu93#Q4_oiWT$|Me>0*%<_vw+3~cw3kuoX5}(<+fLyd5^Ta zw~Iz=#M}!A%oJLb4C|lP?pq>M?&kZbd&ubs$^A#8gbAchnkhe6?pHTd2q^71>34g^ z0+&8|(Bc=(PP5!K%{W4>i->^v>y=pYo2Y~uXVp1~6KP761M>;*FUk|`J8_`eQq1`= zr>406@NZ(NO288?oi0+v?|yvV)IcjYS8b_VKfEJSk&D;@vH)8lgL2FF1%LRSDOBmpf{6f zOd&VKVz)c0N3KRew%TJqsly!BzO9>AIdXTp0=5EgXCCQMiC%knW}jM>Y^(cVyHvbH z{zS=+*7fa`HHd-O*N!{>v$BxH@qR|2{MsID^)G$D=-L&@S(d@(=t3o(NCOZq;Q+h< z+UDxQCdD!@Q>k|AWH|+n$yJN91z^35?@cQEY5h{G?tCbvumJMl0q>2N5Whn0zys9= z>jEedm+VlcR8~>5=u6qu$T^X!7gGbtjo*0up4i^DWS}$aQAlu2@K3)o?i)W{W7MFM z&+H4A%ji+*27ygEmn@?`Rg%V${Ir1>z|^CXj-#WS7j&%O9I5_Fui2pH7lK1>wcPe9ccXxtr%I+$OEBk9!W@^=IRO!mWhOT` zZF{nGJv60NR|bCu+MbRuu=AJlC?+O;4#J= z8t6AT-PSY!+phvNGm~R6I&yL+JhV+eu0oIp1LI&Zza+S*wpI*8o@hSS{H}svGMia{ zvdIN*1c)455~XP`$F;Tpz9{i92Loipr8!+uwt zquvwK=-KpOdonGM)l^0KAgxiLP276voY~N|4I|Qbp~JdliP8|T;GJiCfXB0OoDx+s zrj82|wL~$wQ67;1zAU!i07D^{E^56sB6jgc*+P>6MChiN`YuMtFFDlDcC2rv*zUWd z@l;%=A?Cm$V3?9;h^0BRIR4xp%C@rU3MEZrK;JDJNat%77}^}SXYrW(;C0Jn`s8H) zrMWu$c)LPhe7Rk%@jya2sOeOXX8?_GcBX4PhJtmoSuN+p$wY!d1?5Pj7)HnDA$}CW zVY40d&|}`68lycZY;X1rz9PN)^fnN%jQDNk;|`~*jS{ame|j=hq4`9U$E;#UF4e%q zWTrTY)l^2g)Odg<0D~IsV0YT`n?{4HnCVzHnb}yrTzlUGbI}wsN1Wv*E0ATnPs~o7 zW)NTQ59Wo?tFda+D$>&duOZTc+j+CpJ?OY2nRfdMrD)d@=8C2@FMdoyne_(dlihIp zsodGs5DOqOn#`v}3@F-3V^B#_0N_TbkrZC{7fgw$lnF)rKF30xd_pc~gw_#VQdJ;;qUhTd*68k_1v$jc(DEE+`)GF(yrQSxyChX%@HtNRq(KLQ3+g~|Qi?c!0T|_SIE8eWfD2g= zMhv6&*c^l7;@RG0LA?&Vhfl}xK?=-NCtJ5(AgWyC&9AYSJtmIAK|kL$o`3UJ#g>4{ zBs@Mf=!%e-EXAZJ&3xhaak0v3xqC3p->`2>5l9wctKF_DdgX;#>Vmo=vLZoC%uX)D zpZL}nM{n8oBHL4v)ot!{?A|)DAl-{44TXR0>wYb2BOT5fcP6x)gm1lk$)-O(P@oOb z9Gx6Mp3|-~2H{O|BGLg-5=?GqM9kOqokOrmSEJpZ)Bjhn2kQNhfThJ37hN| zgx_C8Tjj@v82A8TsXFCwH66hAMo~&&brmK~yOq1&&Zs)&)QN%OZ+Tpa;}?R~--}r8 z=4xm_2ZIPeKDey$!*Ds<2`^HZphYY<>qdn*>NFzr`)2KeYSmKpCv#a7CCe`ax3t{| zZ5~+WxbJiod}XJsh#xi*{lF%&cYAZC=NS6haxVMo(>g}dTXm;{g@z-e`e9X*MSkBO zN;kMm*u-hjJawF$gN7ivBoUWKAq%~@@^NWTA0r_aLdW|ISJv=rn~wQuTZZ7IdlDy zz!+c`0{{@+-HpRIhxz2~>G)$qg7)Y77UXLyNI2*IhQUO2o(IlkCn(-bO(1x`DI+dH zZg0=zkK{)&b+va@YAxg&Fom(9z1h({_0^ZD%XHL3wmozJA`+?HXde_WuPi#0E=E_& z>@h5inj2W$ORJc-eY>E@LcMF%-jT`4i=qqBf0r3H@ucfxjs0=lC-{9$c{YD!IMO|o z7Ek^5FEk#S97WLS0r~*5aM}<}B221)VpVvprzDZ+Vqegy#mKZTnV;+ffT*{SKr9zL zKTCpanwvn}4IVW*T?z^g)MfP9!qA_XRya|%teE73)P&C3!V#{z6+Cr zM~MI-^(L=-`)>&3cWCONkSCF-$0KglJ|_Y;qq?NZDj7=ji|gYbEMTKrm31l%^3>w4 zQFB%+YEcR!$goUKinduJ#6e1QH!lLw2NZ0rRG}a;&^fXK=PP`l&)_E>QjrnnQj1{X z_35uB-=C2`)k*}^PVw`DMLWGDum|DA6jXG+2(+Uy9?(pO1XxBsw9%r3Z0gb29IYUT z6`>#GD=vOJ$efDsg1HoJylve65Fh)b5}^9HJx~l24@<_A(rjY0I1PtjaWh%!8x&^9 za(vhY{jXC3Tbl|MHmTXxD5r4zn(N%AUl+VOx8EERG)C~1^?Rct{+LCokI-i?FgjmG z_)J$KoWyN#E!ig5!!az326OHej$6CisaXP-!-w%M`%tgvT@glo37PA#@n8Kbab}GA zwZ5(4@PxrUIWy6p&}g6IIoU`-N3~Nhc=0$jERen_ofQ6&P1gXnEG?Sj^-(4mz-hws8q^|#a*LQSOC6Sa&Kaz3T~+G%1+#{ zwHjq`>c5tplvI(xGu>2$pFg__u|5@=M~(%!g%3=;M1_^sV<3v=VQS&vmPMNrpdj^n zxRLWM=xw0#1{)o77NU7`whh&RxUW217<0_9s*}t3Ap06({5n3~>h-6PL9B{c!C!p7 ze(~$Kix68+D-)lEr3BKdwHK-=?UrAkw`UvI`l5Xa9d`M(e}M;<-5=<9zZ3}_=Lrx> zn^KYV8`9FO&-z>G;K{*E%V?oH)rj4XAWsUm^$UidxBG#3OrV{OO|nva#@N&cGt8q-eFSP^(7Z1ZfxJo4t65w{J51dh8dBA9!ke8??0@d3*NG3-`7XJJzKxT(SA`J1V%eY(4*KT@z{|>)kS*tDY!&5K_xAXqI0Jpeq692as z&4)_niTxqA@$X{y=acm`Z<5Dez!T5UJ!5}dWp9Ls*9$-a;wuDwF6KfWm&g`7!;vcnf)h&!3%7i4KE6kb#&7I-Sc^5jlk)+2qrBygZIHlR^kSX;N)A|n+-!;c9XQ+;`89+^n zi|9x;PmS})w+QizXV1gu?+BLCpELfKF8=`n2N^J~(c+|6T$ic(D3x|poLPZbEqW;9 zOZSb-uWNH#)iQ&K{YJ)pD;GP{@laqiifWdF`hlG5shqqH^AfVZA(X$*v8ThmUl(c# zc1eIFe^~0esusuLRAVp@HasLZmOp8@Q7l_(FiE>PR~GW)Gn$|_h^NK(#gs7p9HjUg7}__2W2*VP<$$MebIv01?oj9 zM7%1%f7eL1Nw=&%!puRGzd) z0Pb+d&wgN^0}_NLei<+vn7`Qkcd;dDlIOAZ87WbiYP8hA2{?1g>q7Gf86Jo?==5^v` zJ@AUG_vbu7K!701nj`;5NODtZ8}Rp5<~=OCyl$>mHp0leagLZt0%Km#2*TabIPA}a zVRVFa#gEca?z^Prs2rlR*mfpcgRF`5=F(e}k#B_r9L3s6yvim}MU{gumIv*DW+w8gYT(j}iBO4t3$1Rk27r(7g{v_i9T5+{G8 zW_a$B&T`FPe0P3Gp4XPQAGb!`QXGiNzbX=;D%Sm$P?oiX2D92=>FKf0>AXqIHt4K06ttXtit_<{jC$K_zr z(}^Z%cvbN-nk{|3?naVCqvQXJ!^)938v z933w+M+`a;fssyfWy<|Ybm<#*IcYpt&OXBNMDrTmMc?z#ZtaAoF_*L6@9^v74<*u) zU!(Dmigt25@A0GY;N2B~%I}{pZ=K0!tZO(h(j!`KdgxZ}&u-jbL}?S9&*IQeuf2Qc zvK@W)pjGe#U5;Ev33r?R|N0icZ_8T%pCW?5-J9l!6$2EOJjqTD@cfDF9wldRL=ZZoP{E_eZHQsqLeL3Qcd=B4Z>CHC$fHwYO>-O8z!A)pZ8)UE)GSYIp9SOM*4kYttO*b7%V6wP?#irI=FL(_^ z1`Q@YGuLQPV8THUrz46Q`!mWWEL0lD<_wem;*S0}ie9LKBnl_*2j?F949cTb0ja1k#=AZ%K+vnYWmdoYIX=U?7RDo^Td_aKc`N-eNz&2#U-g{f2tQ#i z!W@W?uXYfiXm_uP21B&raO*72U~MQyg~VK9PO3xLhz37TI{sjWDvH3-6?#C={TtS9 z7uoEoScwwRmhAp9E4@PbJZ(q>TQt{j{+VC6f5@7ML9P4Alg}Uil>qUC6?g00ejL>Vqhx^A&0q;q@9w2pwevIK1{>RaOU($p768W2lWMBWTTz{@J zc)cGRoPlUn4*~gqTQb02gaISCeGn$~Paoy}Js%La!mv=x7zT&^Bc%P?^1KEk5cTlv zr25wiB1%F5l3=*#dn_G)Fl7H2_$?SgIxnBWy~6*${-L7ZgBB1R;`IL*!v7e%2N=N+ zF-a-HzfTk%0bCqEpW0sLzi@#6DZ}*S1tZu*L7jyC_lf$zf{XM2_wCWWNkJ-NL!;7A z2}q<*5t2p~DJ0+|-~8fA4oadTL>%_IW_#{BzbY5ikFn!Z{m=dT&zoW@R9ffn@Avbi zAJ54GUNwb&7v#v$iy-_u4~ovKC|7N>=?AH~Nv?A}(xAiQ5f=);VvqhImLzJSSw$9e zmK<6(jockjUc0jUmE9`~;_~k!cu6Plg))&~WJ-}b<$6$SE7FpB(0w}SUAsB@HK%XA zd+x-0NZlW)2FU%YLs+-sa3QU>?M^9uISs3#PQIx})p zMT8}~lbkD)KCIqGspkg2a+cUP7mZw2<6>=nD7?r>m9xa6G9Qmg)*o2(ICOuqyZ@Y+ z=VYkw;S4IQ-=-gZJ1ccM(NN{J^{aEg=#H^YN`S}bNqBB4EA^E9Qp~9GRtlMMaz*S_ z{{JcOr_d23kwNUV=Ejp)>NPR28b`CfS$T{fb-jLYjF^+|x}RyiJHe?sq#t?5+O70| z<~S?{ybKJBc>c!G@P5JSV!@pOe^$yv?;C&jmn&uGB?cC?{6{N|PaY0YbNw?Uc0aGZ zq{H|;3t(_*oE383Nj~pIF)Ea;NK$w6`0AM<4B#X7dE16EEk6F zrg>+^`;*Q1p8S83C7jU{8C;CIuaQ5k?u@}Suu4R61s2)tB~=w)WveST(8tQtB7LB| zIZ}$Lw4AF^jPd>VGDt#!0l(eX9P?gP^HvTniFlER%It}h-4vXy z*SofO#V9+$Os#$nz81x)zM!toAz~k&7HFHD}Q8e8>sNupEuP7wF zkEetecvz_+z2Rry5dD8S@gTm~&uC;P9}BWwGL96kl&A|P+4OyrG4E>aC0t+|FH6#s zS2gNC7ppkp3>K0%JBJ1gWj)WAa9ZtD6=`!!`uA!m+9cFuM%1~p`lZ|J@wSvE=iI5Z zG=;NO+cSjOZ{&YMBYzzBKd((}kF=Oc^eM$itiq|ohrj-+&h({SO%`6k?tZpO&yNDY z7C)o@qc!{ArE(#`Q&~XeRa8GUy7Vx{Z(k5a#e#({(m_B#X-bifp+`V^Q>t{N3Q8h~pwdE@8tH~mq}L## zKnT4F(t8U<0tD&5!S{XdRoD0T_t(u@IqR&Il{x3k*)y|e@BKVat(SDiTNOYK&(#k# z{qEb<9DhWj0K#@NfbdsC<-~r=1y%)wexXH63yr|c@=$n-8UuhVD1#E9BZASDv5!m} zMcw>N?8oA{a%FCl419JJrNz!l) z9-Z7r9#Xfj?yU|vgFW$t7O{GD8epofo@Mdbmjk1(CNdL`Sw@F_^;4il3spYeNweI~M--datOUsPzSp$s zOArBk>c(`U?(dJb1xHA2#W&OuJ7?)tiY%KmostJN3@5DqY+d6B3R4eRHQnZtX0 z##4V#k;r^!0}LF3DogW(ANhyvaC<>GLZAxfO~>fX*%m4TnO{^t#UPry2S8u<(Wdes zt;-@{T7z&jD#tx1+0Q$Z11eRU`|R~Hb%LpN7fbBNOnL6_fyrg(ZbyFzgFwo4qgpxG zq2oKrr$n_Jv}dtp8xNPpmADDqZn;I%IrI+LEk*ilGAMoWKh9y1rFN7Xj+gMtS4+Av z>ZEVmW8F3lKit&?h3xD=vnUP_U*IPq{MDS<*Kyz_0K_PV<>3& zLG6c$)xh@)v968nQ0c>5%**er<}jOPtxQYeu(z%cy;a*#I>fgI!zgjU6Tt=%HPc#W zX2MGqicI63Ya{4{Y?SkjE3LkDa~x4$HYe~Uf(nECf;P?OmoL!<7F%~{o_Hh|FX$Z^ zLN6va*$~RrW8I2S!_kV8`TA>?F7_=iI-{dB!~bN0+B*59;n=o@72yn(c*z3>+9JPZTx!r3FF3`|>= z<0FBLT@-gu7I%6;wLoFm|@M}`&ME|PIY?J zz5JvGp;Pk3fEnWm;Pb7rXRz27mEjr7XTk&Is3QOg&9!iI5(A7~jKg4wW|{L)7A9l1 z=tja%P6D0V_Na>ud9}w33^J-P}JFpJ19ev{5(@v;|xe= zwyE2nN8j0h7`^fhGn8}v{2y!ZFxNQM`RU@Ia1Pgv_bc{OP!Z#sSG%YHG0$iu01hdK zuZ-k|KsG#f!@|4b+Nb&4^@2)yY(oJOe?^yydiVQ;Ja5O9kjkEHs1aTGH3@etW%FC9 z)P2Gg|y+ff$pc6Xe3}e#dvI-519^Q98_I1SG4L#86iwTrJKJfN6lahr@HeX z=Swr1Y+`fb1#PG;9bU>hnv%{CKOU-#4p(OQR+q&V0j7f3z)ieSjQqd~xLmIm3zKBt z-Irp;HbZ@5OL@XL*WZI=?Bh}-1y7in_S_)m>~DCXD|g(@*vLi3b*=;XxEE-t?18weptn`ro~Y_mL6m?p%ZYymiGqz8eQhs*X~V6MUEG$d{kK# zUNH+GCR!gd2P`6vaMKNz_Dp8vF?(o1t3 zwz0x?d|34ZaaJa_?(N~bdJ-?gI{S}*&7|Mn)78hxH$@%< zj(ZDW7f+jDIBr@r^s288Za-{3l~h;t3UM!0Zh`MW%!3eZiABi1w1s^iZhU2$dX8>q_b&Xxv1b3Ym?)z@!BA(qHcv|wSvxA>t6soy=< z=RfBv@5hIyUZ*gJeNm6scRFMg{(Lr-0gTZU+}vxaIBOpH_j$v*@tP5xR@sJ8Yk4?@ zA&d=_ZetGVa~4Z#HzJ=)Vap3l_!6y=8{nt;#?!h9FrwmY+_4KX)c2v&9n!EPmYSCN z!YRwaUeqA1{N3)@Ji}&y2;b0ROewK9B3E@_9>No1c&+Mxtcg=N07M;G{KJRW*Ud0SJzC2k2iRcXzD3e;qtF_<4Jk^X(?sz zp#phiW#8aVzZRA~i8-zNL90RTlI%&w4DvG^;}SOCn**P?ah&qI09)U#!)$S{C(S)2 zKs2mVDm}kIKg!8d41xth1#nO=D?K0#^bovb=s2EjL=0XOo7OqC+S$eLn!Z234^a$_ z@!KaK!29@ql(3B?BPUlawr*SQkDn)k;u+PZa}z{+iJGaa&V5>q3X08u>U@b4gN$p{ zLr9L5@@nhfVK==X^A`yj<+>I9V_oX?lcaS zSOj1}G9}hVouH+qeUz`Q1&GF%w&)e z=k3LxF}8^Q_r8AK9QL-~83w=J23yZ()yh2522iQsl$gg}h`FhspfqXRpEh zIqQRumIq)o{<`#yefH(U(Jb`N;3Fj(v3>iR)=*ksovHE3|6T0oW$Vn;ndNI6*|_WX z4xCjBPg_mrH3Od6w#a#|Zhtr}?jT z#?beL8!X`Q7Af9)*6mGt(+S38|Ffh27!&pJe0>tslc%B%F~^KNRnT3S8MQs`*ZbBM zfeE@!+E98$&sgqc)|sJgRiO<-_ppE72skswlhW0mMhnz^_(&CX;)S^KUg4!87nkVd z(M5bki4#S2=6lIKEr#Y;-k{d`n{q_wFm-#qq@ds0VE$fRN5$y3(F?sQ&WUdIlAqe{z&m)D`MifMcc>Yj2WS zv(G}6%e{00a>LY_3&t99|8(TIA?3U0Y8KSHL~a)d+6SDE8OQp@0@ZUun%W7jL{rRb>Kt7jCx{7v(nB)DN zF0++O?I|%p;`Q68Q$;F5VS|CW*jhafIR04h&4emQR|8IWf>v!kWA{Y7XLp6B3AX{k z8l^c!QY~Oq=0I>+hRlp8Pi1O15s7iz5Pa{xML^cczJ=(9H*r93658T_+%5BI$7tE@ zzDXcdqG!3k!;}H4Zi`$#NiImce0Vel!U%EI2j1b!1rFba98>SFwO23A0a`%pib=IX z@WX$SI`8x*v%RKO0ODKaP zvSt&nF*YD65$6fL!w+PZBffv9U<)`PZdXG`vK5^imOSk#?+_gq`r(K#iMzJ;`Keod zHMYm1;yls{ZBzShrNx!Nt3vlaPiLF%2a1ZeEq^@FG4dhKa|&QKYINv{sZp`dfA+zS zy9QD_k6uUfcm$W@)Aaa6t=mFC$lzR}zf}%5JL&St#4zTCG%4+|#Ooji76o)WaSycz zV)@aybVwQj{z5Q~ygWj_{XlQB*K46idnDk0(!Vw*ZELT(R2tKZt z$of%zgU2XS#UuWKl=DcDqUXv0OB9!SiDDIv7op!)J9_|D0*CJ(5Qn_AWvnA)qKa2P z?tb07@Gd!&!*)2K|9otX^Wl$sg_Ft60yFDw-FPk$X`ks=XXdwx)RJzur)0le``#af zOMO9ZHFAEeWpaxK=euP>d%O?XJU*W5+FoPFe>e2m$Xw~btG`zT7vIxlrpR(%@0FeP zj@UN`ytLGu%Wb_)DHzraqyD*!C$BFSeGY+nF9S`5w2xoxdr)Z;vvf5Qtt4cA ze6j1syyogXZA#PI8n@|WxURL~3P(^O{c>qQlt_H;GfxHL8B z{Pis<&*)X{{Ab=0J38sJ$2!FP^6X?Wp zttnJS3UtZg(z@9}D}$A6YbC(J=BVA;oCVB}uM_t-C2WXlwufpE2`hcbo2KyKvX_=? zlN^VXUJgs5>+AQmYE2Jx%*VJf%0Bzkv!hZb^UA(ijjbw6cUQN4wH551TJ*Xs44?oe zWmv8D$Fukl1{y00{FfKrFaGIX6N-B>SuFcIXH32gImdOx@|D^!f$Vu&dLwpVevP<( z;Je!z{mGw**+NRKXCH671eM~DwGQ|&15dyea6xfVj)SHf!>L}+49$QX3zzhMiNRo* z?Q(JOOcrHjkD5`N1$ET7Qn&2+SJ@hvGwsyZr4MU1&(F>G4qK^87dFjb%hVXz?AseD zUTKMwhELjVhajojvY|+g;n=}j2P@i01~s2M%R}o>STf+M!~*@7X|#Yev{qHPV7sjs zTEMZ|Gqi&5GyCYXT5x7jfUQ-iSO={ehh_N;ltTZQ%2F>Y7qQn>-J};$L{ju-1!v6b z!5;OzR4a2DF%ND6!d$AEDmr@_!6jUolhVr);dEAn6vtkhsS}V|&j~T{o{rN(X+N;( z;muxS`K1^Td)8Wvx2+JL5zQn{kgI06&g8hdp|rTe0=BE?VtC_#ev|t0Nffng)r~fu zV!k_VW4=xziuW|!#zrTFtHw23H@*?=b=`Y)X~+q+)!G(l=M?V^ss6lv8Twnc*78Qx zo}t1H17G+pFH=%7Z!!p1O(XU<(G;8W!dm;s>Q8HT;_Fq!4v*&)voh#uz3?RNzux7=pk={9g^>xm?C4(1zm)KQ*I zRy)w(p{pZiH`pM)tx7hCfa#MFm2TFF1$31k>N>o}@=AH_!-P8aZFj#u`-)1iXbRD| z>Fg}lTB!~6m1XPbTuCt%jYBq$nav`gpxXvw9l)X<3o_Cz;oKsRAHOA$` z5)dw5)jlV4mXGKXBh5GZSL4i{Inn5J_ZfOTOakn{IKN}Njvq~jI}&U&4E4ik4-%FJ zF4%8{(u*0p_nGq5iO}q}Vx3g@P}@L}PVI1)J+0%on@OwE$3W`@?i?YTb2s2W2Cgx* zk*bRK?Fb2RJl%k&FKsL!5R|X4NOqd0xlGh|myHNzeK&iEv`}BD`eg%AQFdH#=JZ*h z@mAXqf|20+%Uzb5PcrfrILUc0H5IqvEjf~M%S=klyjDUB5+InfFrUs(AB8|5@>S{DVyw!GcD$CY&WZtfMMFfG~Px?CBI25S?Ets65%&Bb>HCo z5<V&j)1QsAkFkEIG2{{EsZU!#gR_GwQniQs_}P^=3i)gv;)_2%eb_3%ZdRQ9#hX7_!CQASqq>qs@bB?|8I`g;hadbf!mFJ}0D0j*;zqZRfp8wbJ|7XLem9o2K zZ~V5se_joqX=OGL`=6-F&z&APWRqQEPF5lR^xv?OnTu4Y>LP&^E-oe(y+{zdNf-=rKwp~h4AFbCnS)V}gCGdl!5E1-QxKtx_jj-UN zTD!8qUq`n>^>cZSOHOh_Reoo7@`uO3fNUb-Pnskt@r%tG<|6HOZazH6oFO64yme%X z<8df)l2gM)yevUDe50>zV6hB7pvY8~*fFKXzTvwBTdw?YxGrN7Q{DvnN7FaZhm0CL zjyJ)9(0OmtHJ{q_XG>Z1PGRmq+66QTSKPz3oq5}{@J?-lz}1eAfOrjz)g(-0WFV-4G&}?pBr3!+ zAO#8hLWGz@K>v}3fFK7xAt0W`e}I4kK2d=``E02Fy6 zvT@{c<0by%2`(W0^J@lT!ap8yvg9RJlaVJBvUM;fWTSse|CX2!k&uv($HB;i>%Fk( zU&Vp{c!|xNob0$57+hUl>0O!WZ5>P*7&$pP8QwB6Ffq{qPtZBK+c@dF(b+hX{8`C= z>Jc_}G;}bxb27KJA^cgdzJaZ?6E89G&xZc~`LmzKZsz~AWaIePYXL9F@H2;jk^U{i z?}|B@oBS`ue&+mH?2q^QvpJrhm2t_NyBS-l3!7U5QU$uk$I8OW^G7rP%K4|Gf0k5s zGmY=2LO5nhr zP;B=$STABMHdrsGXn9p1Mpy$$9jl!V56j7f%z^JCWdXyAtF|s4Ev2QUPt0k@+sh@5 z_rWfX;8(P0*$^<4?;sK7{h)qHc1HOzxeN_{;bx2RoV|SXZ7Ia&f)w2>d9ZN!Uo-7{l2F~@0Ragj#b$k zhP0;`zVB;zOK3#%W%ifO{+(RIK$&ZIgnOSSZq80g+D*tw?rbIHmn{%*QMEkq+Y)|I z{GDC7Vlj4GXU1p@3aE^R-@dF1g*X*P>5Y9AqtQTVSO{Mj#m-FIF6SS%J_?fQEZ zKAUf-d{kP9U1R>u=%d}hz(nfB#xeH;&z+Yu5*p2{vHkYBVCems${3~M_r3}57I4wR zvFWg*@i`5gRi&w|zjb5$P9STuD4{qEnMViHG^z(K3*+{%K?e@@6u+zfq!mh<`p|V% za|P>n*;O=MezDqbj`DsdLLXH?M?1kQXCuE;Q$KA;pxGL`|E<{<@VCp?$*!XRb6)&> zp#wxf#ZrQ~f2ZGmtLS>~`j0yr+n9ehR(d}>)k?c0@w5txj`f( z1eLm-S4s)pfpB6U-|8b%+Ud15EN z30SU2lfd><1m+YrZEm4B?DTxzkCCdCI`icgO};lLkXg#@1PX$s*Yt^LX&rSJJvs<) zXfeNhcxibX*>6gw*X8GSeU#C@zv`{q4*OERPR$;d%L$nPZz*t`O7&>AXz1Ts*fmPI zMnVz33PODbIZ<5I!*jY(JVln#X4TqRKPM8LL(T68mt9;00 zl4wr*OEC2ov!X{!%^5l)Nnqy%c$$BkA)oAb@3NX)PEpCqKT)Zdu*ha|=+}?3>wZsV zeV!v2{G}v`#_ODkzTUb49-Rx#VP_yh28X@LsX}RgC6}T^xv~QEbiL}^M!*!lw>_NJ0@CjZ68Zj-@sdPprmRS(9O66FAHn-GUv$-*%{!dgS zXImq|(tDHoUv5rYGWJ<5e#8U>YuTKemfma*yuOcPsPr)sPk}X-O8F89_X?TnJ!zfw z>|=s&0+?o#zLoi?}Ap1ZE+ivKb?9Vvc|&jhiUjRT~c-7C+oBk_1O;Dm^aQ0UZa zjcYw$-Jb3AHHE#l-|c6l)vd>dd5+$oDd$2inF#*?hcuxW#b&+yVVh2)gi7(TqjGw+yyh&mO2 zzDd;V^F3d7+2bR(FC-EHH&Qhk`*ETog`7d}#a>I;3oPdS9YTQswF-tTNGvR}tP~eK zE)DvvgU9!U5{Bj^I`=op=SC!2O?GoF-XVOMB&M<-D=BtTBTSFj^}ht|-gVlj)w|#s zaiw#h-)y{cbbR~W^XlkXbI3QTl=Xw)h*(^ye=p_!$7IN3tr$!N;&?oE@8I5Ua%x^3 z#Ktj-Li99!I3QrQX*0f%kIfc%>u`aI%TcvjWZ)i+#>rG5{Uj!{5mt8H?hTgRnVD}j zjmeL$CQ_{ZED{r))@Xy(I>k~d?x9<=Nu^}-k!xSdSFhiUJoQr|xiyzkxe{cdY{tap zmd2#X_o^0^+HJa6CS&U54@!4zFN~WLjdR_?P(3_%M(~i~5H|ZU9t49U^iDqqCwpA6 zp%&={kj^GES%*JpNosRB3r?9SIG+sb;Pmn#2u9*_%fh9S%2Qlx=NO12Qfa<<37V~K zWB9Nbm3E}q6nXxv)GyLaGR`q-;TJ|^6hkCs-Wm5%5~fJG5i)Dg;l$=8?V14M$iTs6wL9xy^B8jV^~nr8(e0T|lQ_z9E8b!wXs2AWVb?TuhEyUZig+MaEE2ms zP(UmiS0FQ;GnP-r;>AsC7It&|w;~hwqw(4lq%j`F?hj|iLxeJen?>s7*b@a(w#6HR zqK910W7Xc8d9rc1fO-1hrT(e}NSW;|-VB&@jEE%vtLJv4Z!D*fhta@C$miRm zlihC+`bCr`Yk4$D{q&&&O-9pi^Oqy%8f~+%$r8J2ht>C`_@DcvLQ&)fla3kDn@{Eo z)so9x@QTZSn+7Lni43LCPs^YyC}IwaKrz0bDbqQ8+q69o&fqYvL4pl){7`2eODAPg zcZ{E;D8?`PL)$Vf zqiJl`Q=?4Nl)nCzlg6ZKs9a8F-euq{ZF@ioAB?>grl>faPS)73Y5XCmNItyk3ESwq zjNb=e9ezt3c->hH8jl9#Xt2Cc&xK4nkkM$pTvAFQmpb9_DH1cDNh@kI)>4AW6pNEd zLWbM1K9O=SQ%w^UEsNJtG^@cr(35HJyG2QIq~KZ6*GJU1c4#locD2r{rBj(eRPxuy zt71<+4;K!X@fd|Mh#nG;_*m76eC;~{785=T45CkuV1~QP!(7Kh9%T~G$JzRb8fWjl z8(`_rHOQB|8!wVjWGyjabMRK5xBPatwXHe6NFw&4ulFVBa+et)*?s#lnO^(zVr;Qi z?-W}qee$gogu~vCZ>w6PbL*+#s0vZVZxI-}aw&;HtEev$YdoeUALf&jwrh+VGYcq> zMGBD)?QbW@c)V`peYYbm&r^ThBK)D!Yl~1Ti11jsR-4bOq(|ej<<`3V>B8KHNettQ zQOMsLVNU}Mlplfeu(1s2QF-FJ{Lv7`K1M_mpGr47Y=tXd)|xH{vWn^uq`o)O0yPcS zTY-(IWA}ok?WvVpB3B$wf53=4m{&JBY}Kq#xW`2985K;Hu`#6cSLzOlqn=NksU&H+ z>2G$$What0vV})Ra`_&m`8;_u15#zr7pUiKGw~0sta*k-ggh>1cwWa zvyk}n>_#Vg-&1*|*viA#4GviDjs_pJo4w}GZW%>k2Kre~lcv8%E zEbNgQ8d{?9n3H`*lChCpj43e$ov`#qzGH;Cg`ZLbu^kS2;6PL&HKVy_SqTiwkW+Q+ zQq_AYwT@Beq^i70)9^^|~rQXrdYm3}r{ixP=Ct5$8esO_U&kWVHNuM~CX zzGo*=zt+8+@LCF@zoE@@hcBMO%?>0y-f(%)j&!!gdwbIDeG$<-BBr=D(6&0>5J$3i z*xJb9{)04{fV)H$yH<6T&FsfKShK~5kyKAnT*exg)gfqbXEXDwSJ=X_!s+*iPp@rt zJ6(oL)Hg1dTV2bqd>^eIxb>W48UF2YchKsEe{egJtno;WgH}&|*;yuPh$$kv+%JwX zz^J6OWg8bqU@F@h^WEOjQK-&r{34Mt*XOfvSd`3z*ZKC#Hm}?Fl_O*{-dKuNn|hzW zhL!DmTz|7p3ccH#EcDpdESWN=4J*iBMl0@+r8(c_>J_IdCPAnf*1d|l7iSWr?ij2m zQ4BgjN5JLrz0#thb&r6>Z6xqy$J->5T@*;KYvK|Vjp7qzqna;pFBqH@~>0+J7p z#|6CaH3+m;biSO~%x`WzU83x<#h_j;eNTqc(8e$7LnNkp@%;ficaGF;K2M>?_Kc9T z1@`*izLQU)UrJ#l7N;YX4*i zd`N#kks+bDo?u6;R9sS~(IpiXQ&O2v;0KRI3SV5lgB4YTui`#f>gLp{6-yprcBZp& zexZzb<}=^1igfbBzX?cBS|0mVZ7{;Ku6_PTah-QUX#N)R=BAc;HX=-eZzYFrAAp0c4D7V`*!i@cj7>!<6)>tK6_O>Nn@TR125b0@C8i>US4=kOC60<}+~#zH zh{J)^YJ>7Iy+Tc*@z*G8UUxc@;t#KIN?s|KXu%ArR(vV0-MR3_P>?E=!eXiFTqa$* z%f2JZEskWndt4@s)LBgLvh%)x<$`-ieoiDr^prlx=(Jd!$ zaQKGU4)$GcHS8%EZqaq#pXs>-&03d&7c57Yvc?fo*~s(tas=<@-O6=2ZU76PWNr;O z6=RTc2-NiI9Z-QGNRx_iWOJ!xmMZ=5Z{PfDi`q3xyq515>s6gRj{JV6T-)$khg6<4 zSKTNmg7K4CcbhvVi=H1+hd45s&;1Q1r&kl%n4XPz$4#Tv3U0ixh67r@bgD+o#qR7Z zXfo>iVOk?WQBtjiQh5MluGn6jjOX=1ca}Dnkjgtp70E=}oYHdw+K=OsC!xH73M1LMWX4->s>{?CXIQjG^Q zq|v!c;{~o2bECgslQw7U&s5|W4oJvv0GptXyq4qzrFtLRC+Zz3XccH2c|EUQ#B*?~ zoviKiT3js$;#I6<*}tl318?-jTuLE~mFsq{aBQvv#@=-&8gD_6?->)XjA-CMC>vIW zQjQf?zq9(kEgOG?U+0*O&C^5ZNIwf1!e{Y#b5oII#FU`^N}YBGm1)gBbQ9&Q zs6sj+qAUQ9>2NUV4!?eD*%0WnYsJPqIH}m+tYZN1S@~91_Hai34I{aUbV-o}wK)(i zI+FIU@241JEw86_6Q*X?i^zy2Y>gQwF;K<(HJOwzcz9k{X!Dbv5Oo(XHrje}Vv=U~ zo^6Ir>cvhapwL#px{`7@1FljENDADctkuqcthHKuP18MOX%YUhG|Tq*B5LQ~m|Yw3 zNslPJdwy+)vuw-79;0_JE%ZxlVK`l*>1x1#0Szs;xxbFWnd$=^1aHupRm#773jjX! zQUzd|4!a?=ERUDiMd{oUD2xWsNp82;BN^Ng=86To>71*V+Uwu`JuGP1ehdIkvl-E3 z_33vt-$z36(}s+VhIaG)7Asp7_z6d@Yj5-Z`_+Kf5&$5R{DsZ$^8Ej==-)WN|F@V3 zv*nhJCh{cW$Sm2uhT}=GyKmgRJXmanGab#mES9Rm`?8qMJ5q_aWL0`_YC|L^&ErVZHI~HPxVTN|0*3f`F>+P zirMY_K5mPZ{eNiAN0>Hr2(MCDsCMux4KNopHO3bi?zX zAMfmpX4yY1u(o+#j}*3^%6N|WRHk2o(_p>zLQMI@M(&O?j*LntVCJb^t65I(S8+bh z5e9G7x4(RXgd*}PBXv7JAkyLM0LvuFqZks4_rG;>J7jqTAD^@Ld3%a|q&$W2eLT51 zGESjKSGt^*xx76cKEJs*ZI{})uSg1L4i;K4kg@Z6FlzH~cycvf^ZtA3^YR8oEmm^5+E$hM?Sod073VgCR?tsu zWH&6~BdaStu}Jj63GOkz-PZM>dT0A0oaavK9cRsqGR=inl!0~OQ>Kz%;d|3QvYr78CDMZQc1V#FJIC6dzuLWLh+`MgAqS=o)xjD7+L zR0(7vD_YGbC*4BQnM~83Q66>;roNRtW`km{n*WgBPna`Dk>ck1_>R8^6{2Lym6epz zi037WWMw~13vh->9=$brpJQC2PYHi^a$r?Fgn>3ZTmxxlLNjkSX-_k#AN zdo1W5c>^(8^&Y$9iWOHB&N&|9icKB)cS$`U#ug2$^wsvSH8D89ASs?J&+8RZK) z<)X@HG&)d@+rxcv8x#jROh)~&yDPbHR|ktRuM0=@2J7}>8O%iy0A!4>!|)pafZGk8 ziCVD2GSPxMyUL|Ul$Xn(_kc6>HG73U{E%w7sO%+~dU&pj5z99l=fiA)z_qN@+P9i8 z&mxHh>Z3FpeoW0fsuhTa84biwa|H1{-0j7|lrPkEUum~qK435?OgLzez+coodru!ikPII`e=AZej#qwt=Ce7N zAr^ziZFd9zhF;wOea&twGyQV@J~h_o;%E`0dwPmOY=qbIS~NoC2vTOio$OeoW^>@u z^C$8eiN_ClhQ%1}Wp6v1Ljpjq1dQG2u%uyi2M3g!iB^{-|;=bt_*y%H?fC#X3kO zej>lBB>k}-jru|(YP0^o&YO*O{;t`lLvgL$tRYo%My*Iz`XiYikIZG3ra#B^9veUxuod|fu1ZU(%=jmH}l>F|}|tVF&i z&Lfk!zgfOkqjDs%`0}ENcfV@7-Q8%bOt;1HUf`c2t`jK)H!8wJav2Tai~=H!-TH3Z zq%Q_1!rrjYt5$b^kkg^UHNuOLfXyK9@$6Cc`Utb217c?&?G>P~)hu+mbeomOrK;sh zw-Nj5S842zvkweL%DOe&E@m-<=rp@LbZ0QDluVzg3I~}dJFIb7tf$}+l#%mgT3zn! zfFpqu)5arARs(2iWy%=v^^rl|U5zwm@m9wwP==$i8q&ct^BU5>5<3gS zw;X;cVUB`oW=4C=c1umh`>h48DqsGU&L_6(0p0ytM(*fg?XF%Ijl%Hdac&`1;aoI4zHWHl1Yzu>dEJ%e$C^@}*rJb$V2a~9x$fVvFPJOJ7-P3;``FOn8_{!HARB%1e3F&AuJhfPH-{d~= z(6ZgKtv8mNW@>*vCCeN9U8`^WD$ug8aDO8b6=JiJzY(EDR z$+iSgE`Q^Ne?zFJ7xV%H@^QLWVe|2V?+Nm1#7H8cXs^>}~gZvhtJ5FDlDNc~HO&(ANZqAJFRHzvb&EY`L>!ZD%*-G6$L{@6k&6D-mam4q)p~K#K zT{&O7$3EduPsmX-+vfA@o3MlnG$gEI6b2tJTzTE4O{tbdE>_E3hO!#EJ|pG&dP@}$ zioCDOo&h@opu0NUXU2*h(4F33q(ZrjFI!S6d0Z;Ax*veE&b680w7bh)1(I?3Ct&Aw=SkqgXm1M^~xKdN*9Bn&tD+6u&S0Kw_G!yS+2NA8`wiP%bLWs4Ers82lj+Oa?;< zZ||+=+tdm8J-2CHiWnZF!)cClZ?y(|nPp(kcoa#IXX@M?FLhj%vc9q2O#yRCAApd! zVrvX;9SVmf>=fd&T%WS;mX))>B-9YZ-N_5o{hN|;xExGhN)%Hn?i^{3%N4$N23A}+ zr($!e2u8W2u^ETk2nGnTPn&Ao8EK|pYF5mai9DaG)P#e3g*#T5#qTN`BPf|g6u5PL zH&>mDdC~}`#96fL2j%~?o0(%dLZISGCT9kL0BEigb4~sh4Rr-k=#dOw&8J1u&Pf{8 zvaUeir}`4=uv57#zWkrlx%aqOnG8dB4mQxpC=5DibKQco))~oRb}yI`VRBF!JcckC93`g)(QIfa#$Na?1 z!2&sl6A}@B?2{dSh~x`;!{(02Sc%x;*sVxfbnf-_OJ=nzS2FRAyo5B9?5qC3{T4j? zQd25c1M=36O7sWIA756C?|2Zt2&;n0PBuJFLy`h52kq3_d>^2KHKTiLe5ReUL7N4> z$n47mp`R#UM^~nmRqR#g+Yb-H%^Ey?_P@)Au9$dZTNI$1LnK<*_;ZO^)LU_vK@0Jisn9euDn&IYL4a_=C|eJv)zvcoB$+>`j7(vJn>QM(02fO7k%)$z zPNz=($(i4zOpQyPSob7q90xR8E(9DFSD8G(mZ{fE`eJoD?R{PbxlKj4zup|m@hVOv z?LU3}Rcs<}Kq+>RK(KWDg=n+gdRuidm|B;|I4A;*F%|`Wn;{i^byPhiS8>(>INC7F zj}EWk2mHUM))JN=Le0^PEY!Ms%~oXWmO#B=BHjRwbz9~Eh(PTVFmWPRl7%-!-}UEu zI?R}QW+5P;4)!pMs9Z1&VzEZai@uPE8`nQ;e(Q@5aIHS8LNMY9%SjW8kqOldfYXv&n1&Df*M-C@eB`tc;K`(twcw;lF^v+1s42H;38#vx!TqEN zZT&(4Y;+p-}6SvsW2v7%NBSKhBAA8QwLVcv*T##LRzi7(0qj3 zZO&+@c?x00wpyM3 z>pdTQUb`ji8EhMjY@zYE!G{Ltq7n;>yi#nYvQVB>q(sK&0y*dEE*rEQo>;kX% z+s38C53F~4df@^(-F6gL6l?6RF9O*|5 zMPt5f4ISm4MmF$xBwu@_?gyT>>Xr#3&}z5Mty3va4~Fw9SFsv=73X@D6d9C2m}r~W z*Em`lM~P0?O<1WT1jWTJd!*!U8xA7>VM-ZLDmJrmD0O{3*^hp4wPjd8`e1*34~eV6 z25YOsQ>Qg^4@TLQf)FmSoTuqMZDi`55;d#wZih0S`;Tz~@5uOAsu-P%?r!qa#ILQ)qx5|^|<4W6S<*=uIwK#7#eO8M- zZbT)!kV56=EQ%MfiGlc8RCk%9S*FuB`8>m_$-tOpJ=F(m=j4}D^0ghblL>gDR2^d7 zg+bM_P(1Di&E-@tBDdQ!P$J4k_EeJNrq*$?BDK2Zq{(o(D5XR+R_YH&N#HmwU%caW zYP^bww>xt|uK0u@Rc{LRfHHAzG;Ap@&snS&B>+X7p$>$GLhLhI@1s4$Isy!|6w)Fi zaQKUPiYR-o~&>TuQ=sLy~YrL9PdW(>LD{TMMB8H9We<4i9UUq&DbJ3PFD`^M`lyn{e&#;biEHpE$$Zec_k%85tlhTbqQjSX_{rdy!A&> z(GNVzu0Rk zjm=%?`w}|sRf~af#i;c!XnH5nT0V-P11O$Hqd;FgyHAU&^lNK;TAx;4G@z1RpK(<= z`Hc`m%9zOg3DvR6be|yao}bp2ssgjzlC@m)?0{7EfR9x`1>a)4B%f~jk$!MxMZJf2BYgE)Wep1M^)i_-6FDVgORMyG$jQ1^(4+l8Zy*L5b6b_ z63wpH6&=Z&<#BrQeIwdV5R#7@t4TF3mlk<4DM-_nGgI9`yVUaJG_2D_>QY%9qIfCF zL)0b8tE6M3*W@&110`BlfJOY?w>8ut-2=+IqaDfzD*@`dI2zP+DSxb8$)|ffFf-5W zoxmf^{HQR{2)>#ubwsCC!pxoCnHSHts-y$-6=$YWu{4Zs93gW^wJ19ws8A{kKS8<1 z46C}<==8HKJqeghOy(M&*I9=~9bHBREn)RJRw}s<H|sln)$PaW!rVm~qgr*%;HoD4bdQA2;?+iebB3-toTt2T5(WXZkyt?czC5PN*!&#gR2DZO= z8QcjrT~`ZLbnDtbnCj@tyPNQ}f&F-#Vb_*H?9{5?v4{5JV|MqJ(vE4zhuXM8$DpqyinrwV%qrHyLWd(=d3Gtw9-XTqFX(=IXg?YV1ihqdRS1P={+`(@{QO# zY?~{rf%HT2z32*+PIX=TN+9US_Xfb;P?x@lJ$+&q-{OnUn~`u-zAMOjHFeQ)VnLk= zoqkZ>3+y%DSFF&uYJ}8vR;)S3B=MnuZFFE@t!Z(RZbPL%? zM?+~57=~)$UZ5dI;jq?49@)F#VQ~_c-a8#FC^K+&YHUF-3;;F-GcC<+fE|^*@M3j;Qk*dl)uTONj#AbC`WwTwZ5EW1VGS(gFv`RKAL6a2P z1W-}$nwHX_Ye|V3+ke#YPF_Zr6uSZ(*O~56eW8#!%MmH?AIOmX%^bo*zHYJ|dw6+m z_3HGF{{tA5H%cazB)IHxIW;I>YcCrmXs^_E#&;!Ox;=n;eyMcynQq@ZEkBvf_cLn1 zY=wfhFYJLf$XB~{H)vBTrLs$ab(l%_5z51vlcf3Xhe*Ul5gV3wourJ2*W*F6@)3!I zB)vp24!bp?I<@yrzXB$cTNQr0{;|i({7zZrL__3@g*y9O+0QnlgAJ}Ss&{k)D-5Mx zhVgcf007SQj*YGG;duzB#85kpI&>bnfk8<#cc34g+A=_Xt zwY(3>_a5A96N(SjI8umL#jxO0fz!BRz}1_6HQI4fl7Gvks`O=V2#&3YFG_6WQ@b7L zyAA801^F2}Ze#&7J&Dks3P-JX<}DhoE;oYQv9`!o=Pa?pRgFsDW-xQ9t?U}oKSthP zSEmbzOkrm&S_S1RY>=DH<^*QOSL^q{YTd^laOi*jN~u z@#_4hAD(5el~XR>zTy;@%E1WFk0s!9uTPeb%Z%!%&M2@|y5_vzB4C(XpuKCoY z@i+gq6S0Q0g$vreGKL|?ii+o!)5(BWxf(#^S!}faMq7UY7Ma|C?+_Ub)%n?vlrZJp zK>vD=5>i17rDg*zHj71&Ak3Mk2WzeF>Eryr;xkUTq4-ddnH({j-{M9!FwSnV!T69t z4scI4OQ{+SrmOEPG-r$Uyu{}iv!J@u-Se4K{YQ)bw5m7WFkU=_7vT42Bfo5({ysbJ zsw7(5%A4ryJ*-ao<$Ug!WCPR-`1$Y?)_+bp|Do-kYyg?Jr|cga#s0D3|HO`2!C)fS zps!p0&p!Q(23zX`GS4<_-`d9fj^r`-Gg9Y&2?pzmc@EG+`d0N;@PF5-s-JN@DnXUM zdtE;Q3?MV6v%8J=cb(Gv8J1KI{~L-LATWMHMASQUT(FG*LPV{*lhl z*Zfl$K3YH~|0C@A)!%~uI}f0{lmnEM2I61W!GC0U-vng(+`rsD{2kc^QWId=Sc%;H zmMC*$4`klo;Cx@q{iU_Plm9oce+}OM4eZ~O_y1<>|Iahl-;e+75egbH^rSlX3!R`E z0A)+NZask5-A+#s@U=T5vA2e|&8!f<}y6NXn$_nHxM zaW%g(uvTB+R6r5|oFYPz94qm38r~m9(*FGj2J7qf+-|39j4PcUrN>Nmq1kp3m`Er; zgnJ&O*zFG2sM1&MF$-soyLaTWyyODt{$LOJWnln849`~DePiUP2{$##{1D+`5O6X5 zp_uSQMyz>5X~1%8GXoJX zqJu%9DV*r>o5P`Q)P7EO>#zr@&8V)U+LtFh_qLkOZWk$s?Ql9B9U&ZIaY71t5MB}LRWmZz3m?1h|upz5rkrg z?>XxA8D=iBJ{Kmt7c*uG|1k?Xqq=-8H0D6;wkM}>kxVa(M0;Uhy?OCCrNs1Kq}zLG zsE#+tlA2ruB`*#`%Qvs@vC?eyi{vc@8M+1fzDhj zcP@pTA5(kU#!T3AwHd=Q*R+k>KNSHEhObybfI+wOaozO|lbap1d~UGXuZzt|E&Pqy zJ4)fEu_Bfty3AGIND*x@uM|(()k<_h5u}h?ybnL7H%wQzKDELBv25LALsd@i5=xLh zf^L<}g10oQuOaI$pqJ>&Pf+rhH#V-!u{@PZQhQa%vy8x~N>7pKsUhV~6h}?Y@ z{L>JhMEe~U5t49hX0Ww8R-hoqcgf{^3GOtfc1)&)$C=@kuXFeoZX4|g_aFb_rw)Ao z*@Uu^L|)1@ZpbJ>dsboh5@V&66hR)t1jQ3%o42LT9@OZcF<1PAgx!RT5V4WScX7Ev zHcL&>hJDfI%LZhUUb$L8WM=#E;{%w(ZOw1XtwO7r5ugDcEY)JPULExSA)j#ob#usm z-fXG~;U_CAvmH!mTA`)Z=7cq((*!>tK}x1nByYCznapH3BjP7@XCt|McdnUPFa#kt zCe63Wf!ER7=5HnFg|^kVf5a7dZ1d@Fa*hf?;W0GhTsg)v)&WhQ-t$uu=4X9VKC0`luZX_3?# zVqE2-NcqMQ3CyeT> zma!d{fdDTOlkaLptJy>*qp8mUl0+_6lLzk*!qPu}9omgPlnxR+03c$zV=H$hGoGir zbj*LrF|*iVyqGcRXUw9Xpx8^hi2IKQVL>hy8*Doo2gQo@4Lf@qdLHgidwgShdVI(^ zNkI{C$dFED{uxPn7f++wB8L%yPXhZP3KOz;F<+6wXgCoCYcl^^St>K~TfKJxIc$`7 z*KptL6N`D(FOhYNfaL;cGvZl9&ocSE!)x*-i52gh_HPK>PSzk%$z&s`m6x9&Hj+T8 z^usd$SZn`d+Mm?L?LiScmm!~}PN$w8dJGHA=cj-Tz^XR{$G+bBCqNAmnn z#p_~*8WDx$6V z3oovK8wbV!MogXUA}qisngX{u@Ol&b{t~-&kL>TK({9l+aa(QwmA0@D=)2-9mSRr% zato8Bcz_@(M@!o*FMGgpxWx_`x{^aZu0|b-Z(T{W_T;jvvHc~_%pXp&|Eg-&^f5;yxqo=l+_46n~Uru+HUq__H|u~TfDcoJ9r3WfhCAgFBDdLtwf zIUbeY2MX_=@k+PNt($3C`YQMp0Y1~2Sa@8gc&9wS%h8;^)xK$^)@TW2$FE9M0i}Zo z9~^-N^K5Z$@_Pd0u3xpRiMzA z3wbDRRJ8Cc)+kx7LxtQUk}wN{c1i9{T0+u8af19xxb4dGBK6k3P5wHe65&+2>66=6 z1blPlB-~s4UyO}Y0OIS$e61-GXr7x;=vF8gDT*Q{t7sh@U8#Spm9<16A!@w;F1yQr zS~r|w<6FeeD$DU|r*BXUGGwJr$5-I4gig*!UY8&hl`~cARHpT!{?jVmGc!zQolcKn z)&0}l2jBwhaXP{>B@Iym_FJrY!nn$Im5-%Jb$0Hsct?}ncHi8nCf)msaG3r27nq^j zumnP}I=scuNwLZK2vF673 zyrg!dA}TbF`9FoFLxoPQ@+B^}FP6wq^p%|LSQU{+v9SjLWv}V;dcsAZGgMT@Q7cn> zhIo5tLAS%czzy24Kv;LiVKdk&ndWdj!ZjJr49t^A(9q_0*z9kqbl&$klnPch)bV2U z`YK+g1G2Yc0B)0L$vRuXimBaU&>Nbu-sRULBpo{=35Uk$izbM%-=OHq(x~rKx8Ksq zsPEnYwxl2^CN6Q&2e$%oZ_Z<}#I2zvRh*$ubleV`cB7}Y4#Agbdxm05Pj(4>-au4w z{Pcv(?XxZ*0&A>PPPY{O3oW`88xnzou0)-2sY)`6(Ag6KK!EGM7l{}vu;%vuAg4XL zedhJcT^egrP&(K|Xsq_QxY`}leXWUaJvElMzb%U$Hdsd@#>WX(ByyWp63c|~R483K zWS9es_}4V4Xq4zmz$4?}8Fol8Nh>@|g2MYYEz_4iEH=TgaZ%DL*jBs(b# z*vW{U{U0``)SB%4m2F*%vS&l%a;MBH&SKwXwiD;NdeP|Bsy&cBh@q{v6%yF_$h;&HCFTDx5VYs*~_>;5WepLNOc7>~;h`TEE^jlmXRce!0(;f1GA`qQe{?xTb= z9l9|Yu6 zewB!B=7VaXCpo8QxJlTq77s=L!Civ81^3_%3GPmC3+{Gs zO@QDMB)Gd1T!Xvo!4llv?d!agnaSLHzvnqW`UjlTT~%Fs@3q!m6+=z{{K)0r+*}4U z-WSSuK0yuv}3gFKd&^Zr<@? zSsrL*jnGven=99Qhsp7d*SM*cMw3)%GEe^F*O?Nn%~x#l_M0AnvV3AL4qf(7agvaD zhYUoPAKmRqpWCr_X8s2f2S-hkxMC5R_^s zl6#suBkWR@idmYqQwc%>AoNF9nZa?7f+S#zu=?ID)t@LN)Z}*j32}Rj@1O}Pn{xgY zm9(mC1}BzrU$}T~NDPZu#1ShbTBJN@0?bOKPiqbxui`6ebp}FJUl&)^UmY-w=UYW< z%BHD`Dnkj3y4lB0y~D}sB4k}}^KBQf2jpHUU4nI*o@ZX_K0jpW-GK%-r0!&f2(h>U z%cQT3UvcW5r)*&0a624r;|rCdfwiaYc(v5-MiNIY*DdpfTl+Iq-X|oYPm(bdKQeZw zrd7iVEcf0a%6@&LMOBZIyKfDy!(uh+eG3rfmsaOd#WTf4``!VvInm^EpK-~u8$ToD zH~Lh_rEqkSeyI_QjZsKt5%CrL%3)XTB$#}T;SNkI&Nd=~Vn-h&&k8b~cU1k)7=ycncofH zQNxNC?`p)T3KvNJ5N)_I-Asmfyf+54{=DX~95Nr$^uJ57s|TCr0_H52EKXZU&WB42 zj3b3!p}Abe|9`Q_A+sNrlByo82i~1 zR$Jwe`8G6`m&X}=b;zQ)Tq2v?;Jyws7|&?Mu}J5Bwjr6TzJbSY9^J*PpWdjktFX65?Fv_n-=2(gMI^sYN)Tay%LFPgcQ6>0#92NRjZAD$Ntv^N$D5Y^ zN56i>{pF#Rn%hAV>*APY0W7m}@fR><2stWz?>DPe;+($7E`ZRUnXbrFHnf-JslbgS^C(`gsntd7$^W26!^GV~<5v*41F{+7 z;m!3vR7>eefgm`%?=9MPsQ7HJ;4vu2bM$A+wa!NzB=}4$HGx{%ZGN64QCpx5`Tm4i3AMR8hse{0XX?7crU9txDp(f?8G9LkS}&;7T{)qg_B+ z9Ie(k{4RhVhgt6}&_*@VOk|5ga{{|z_zFIONWcT?5NHkpB(NN=`({pSqukNFa+U($ zMDs%zup5Q6LgkM1Aq^05h9$tRhZi(i{&c9pz8oIqs=I9StyYO@)oNf@ey0ky5d}x+ z5!IXyYnlFNTgjv~D;DWUVDW*^0l2@t#?Ow*Kf%?zBfz;O{QbRQ{gSBZ%no4uDyZnL$ z!L8BcKq5X@?k1#Pt_z%yY~O|o@;@)UDFc7G`cH%RNev>%B51r!1qYDRlLIMbkH!(R z&+N2hCUN2waj;uLZla*HzV8*eN_(B{a=@1o4db=UPVNGADn7TP(k@$>=zNQ*5A!YV zaf4i{3Q@|ebk`abs;N{+0!0|YLm?@Sn}f!HYl{b%dlh7x<%s#sdItX^;*&p+_YpKR zj>YCkmdDXJkQ?Ng)~`q=(ZuL2-psRJcf_%l$;B$Bgi(qn5WbBf5vn^#nBe-hKV28z zRz;{t0FU{4aw>oLp3sIwV{WD0E+eN){#s^SRvn&Q93ojE+Oy5;wpvYD4gM({UjT-U zu2}Qb$ipKAYL}lby>SkcI+8+ev3938!8>8%0}y)s=AbFZqBdR`|7o<-0o3`c^jyBC z&r*`(y<9R=AH|dkZ5XH1X8VR@CS`z3QpmFr=qew4Jbw@C1|)eQQgqC+g^F2(uG*0U z@yr9J6e6pLMse3c`)IwgJ7cNW$GnP8-_e*lUT%={VQDqV8FY%1RuhSYEcg z{fAqp=r6T^O&xtR!#nl1Sc8cPK-=0zt&qN!{*_5XlWLmtn$h#>0FH>ac9VZ0T3FWa z1%y(&$jg$)Ut$OVZZ5mJ-3kNrV!J+XESKi@*w{ws0Vy+gX=F;6?4{@F&&Krc*Aktg zn&oG&q((`iKARm~0&cb*ZeOdy(6PnlM+maLB`*E z(Z~4(Ni9D`ilxw`C>C^e&?x^Npz$Z?-i0L^T%|T9v72!c13Qn_#}e}iqn+g%ptr6x zf?zgBeB`}mlNU5Lvkn{{qiT_(sW-`%Rewkx0v27iSf4!ai&`1Eo>;*dW$Z*%l&m%V z{Nm)X(+C^9u98I+~l?tHyZH%HIP5kf`rzirxFu zq2lb_k7h?MBVT8lgxDY%bn0V{Nl^hevWkZ zb57Vr;BR2;FTPVK?w5Yu@nxU7wHN^8q?X@MNo6ie+)t~T4Rke0c9_e4tW)RPBy^WV zqgBX302**`9cP%$0OzdO3jmhNag+H{taixhAhP*zy6YFMBPsqhoPZBo?knevN}V`T zy`I|Oj%?a{4pxV11j3@c)jWQ{Rw9khbs7T6OrhG^=7IdidP5LHT$~Qj zy5ow$pgJ~nH_Hl?=vOc;*4YFLTB@<&El~K=!6(S3a(6a_`y8#5@dXsW5C^Kc@n$;` zLT>vPj9)o=GA!F0`}fQMiBdPvTIqc9OUvQ0As6g=sHB;e!m9Gx$weQG-Njj^{o~{N z&XTtS7#?>?^9SI1oL^l~f%lpyoo}6jcL- zyT5f=Q~TDxT4L zM#!p68Kg8-Uar?#>^S6gA&q%QXh9u)_njPqT;rwmR@lIFUbN*!q%87zVLyTnTlKsA zG9LQac53l(+y-rp~DQig%B;)b~=6frN&iSM_5v?z`q#X8KbV%5Ms%0Y0368sNrKV`XE+!4KTe0E4qF9M_HPr8M2W@AyO z@DGDav!?b-jq(6{66Ly2ZE&C4!_DHGrg8s+V%xM>6}OQfzAIWZ;^cP9jKm@?;(rh8 zw~BFdaa%Lmc%>!aNgJB}62;fDeM2ga6ioxm$*+6)kE~26!mmCKUvll8IPACgtO!xI zOKLJhzRlqe*A3cQi*0AoSGY>m(19YWFH`4!0U0M@2$GerUlcezW*-wb{~`2SQ-OpC zfPtUvYK{(t`Yj#cSQ7@&CM#5*KJe{_Pc)p18{q``J--U_(j~wTp zN%CKn>yUsH4RAgF&d~xoftrzU>p4_OJlVNRJ2pz@c7wq}+KVuyGaHXFJsO(zO+-8= z|KoA~xm?4+I;rxDUV2VrPdq)&ODW_iCs=8B58DSk8t7!o?@W~(gb9W%I9~Lr+n&!@ zRXO|%oc}TM8c;21s*A*LH{Mn$wdvEhxL;wE+$+pZ4IIpz@3r;A8)s>5-@#$?QewLh z`QPJ|dw!!$|9=W+eE1+ph{#NK0QXTOSe#OcdE6K!l?ZGEbk0{#tzMWwRq>`6w9BJ2 zOhYqW_nHpbHcBjv%Sa@cEZXY-;b-=X-)dl5qo)WOPIL=p1-Nt?a);`LF(kW)0f^7#of4no&5@FXSsFQ}*kKV7RKBPDU?W zs0XMUH^gFbl-91WV1*OKGG*861FR(hH>?anuQwT^f9j_Hm@qrIhiJd()+hDy_gLp! z!&Pn}_kS{_|Ngd@Vn;h_-DX+-1JG<#cJ9vhFC_jiNtx+q1t}ya-2d&UdbWZT?TtCh z+bH67jh*6P?|4#Ez+Y9Mv@0+YdS`q7lf?h=GY{r~K!>p9Wy!2{_f}bRrNxl^P>w+s zIf|w4avGfres?(5{yvJG_2!7i3o_B5X~u?+2p=O-+(0?sj@>N%g%GkeGTMps>{kNv zez7QB>v{s?c~)HUOe&+hyX9>Xtj4|HgQTX=UR!HENI%I#=#-9Un-Zv&=ndH(7AoZ! zE_~*2jgm{|!~_)mK??WKsOXSqd_TZFIb&uq(=i^??y6rl4CqE+O?x!x92>XLSj{2eD$kMp@o;nVBM=4d5y|`c%iY?P&yVk)#LltHDqV*1^+Wx= z|E#Ki?I;rW#Mf_od+P7&EW;k45wdNXBX_3U{8n&i zl}#>=rby^DD*77WRiY`Slv`IvMv!Z^8Qv~9VpST=c;w2*%@$K*QY%OR27N5XTl}i! z$|H^p3h7=+9A^H4T-sNu36GKG#ziNlIX;2Ch40H?U{LV$E9fcQML!~xMSU3fitPJz z%-k=Tf}B#f>y1wScKT7j&5`I63c<(Rf!O`Wnc}&ia8gzrJh?bJHA~z>+`j7Ve)z_W zyrH>F(VoFx+sA{#)lshv6TDCk&<>mpcysIs4(-Isi#>DEcBY94n^DW3=NvoBp!55k z$JI(s5Im;gbP~K~y&--6Sdy_jb1tgWHskDevTwg?A+O86@sFRI02`aP!by^7lgvp? zA-C}qPM)KEcjfe~!|nK`>FkzGkov62CFP1nxwgUj{g-E#eZ$5IVSmV7bUq%Ztyz~1 zfiF)|LXc2!C%#vsF9kmrhy6^9g$a6*bzMwKM`WR#3+D>`O7U|D0``H=XM--LfDj^d zblQN6Y`<6UXeaX!;Ute+>yOiMR@jmcY&i`v6YR^|M}}LTp4gMp;_i zknvX-02Hu#d(r(&c)#w0JjfOxL3W1EJdVOh5bDiu{aWtzPzMUv zuUslpBen+OG+Ir z-$hF}=Ym;j-pnTS|?QJq!Dzq`gEcoTf zu8odnRTnyOb0~4}k@5Ho{Cc1Cb^U5wVId7V7S@^NJwQlDOYqjl0StBzf%`T!@4!Tk zMBX~Z;buX`r)2&XZXDY8vguweIpHKi;`*x17VNtZ*O(P*tlsra?GfQbeA2|$U}+Q* zUXw+Us>(|HBHe=YhsSFSi-qiD3mnMa-UxzR-4ylS{cT1fA-zGf$J=0G{*ELA4PD(u zI86ZQy53xs7{>)xogm{QwiEsA|(8 zY`3Eucvh$(Sd#slN@tJSK-E%BEd*?a4H_~>p!HI#)$-$Xk@i^JilX}?hg+n6IZgQX z5Unjh=u454lk*?W$6?VY$jn&IjBI{udW-m7VUtd6#O32>EK|UG@B?8Qv8OWN%Rmas z7d)Ej8m?E)qsu2u?+FQ!1m^|?2YV*adSG1U8s?GiJ%7j^)DvW=Kvk~im#?WXMK$9c06-||dLU~AKk&K_#g zB0^@%byK2v5R|N91 zKfgSo1bPsTc`0-b7h1IuaA?U{=|V21a11Ya+$YEG$lG)P2TJn&xo4{_R8}bU3O(=S zyL}TL&#ThLI-z2<5;FF06!6$wwQWNF{wq| z?*?wH*_Kr{QOz|x*}x<+1^OG0jDQN8vI`myt)G-qE=6#Lc@8S#M#`^2waSP}B|Bgx zI7+&pw33yv=PBo4CXmA-5U9^HkGABJ}t$>@3ZOtY&pje z87%U{N*Ax8#VRdO?!GY^MjR7j1oCz+XzyiuGkU=L;QRs1>w1vnK8pXQK?}y~x~x>M zb@1ePsvr@aHto{hXJ<{s0^F4M#HUNSeQ_J4s9p-vskHYUqXvq76%E1L+=9ljFl@#* z&oCDmj1m7?62J;!@`S{ho!9wU^vebN6AH0cs04cZeL;rDk{ME#H=U?vpe6=-`gq{W z75<*f9;ctoDmF^%S#i_~#1Y7~;-jfN6re`rY55F6#^C83*iYwO!KhMiO@dDG&t{_P z>rO?j54%s->820VQ4G29WtI0?S&};46*3*KGu#4w3nUOk~|skZLT_ z$>a24|Ez>5U{fB=c5Cc;CdIll_DM`z7B)Z31r&^XM zmHXp24OwAp5UvflX-36!{S&fsyU!#P89=_R^f7L0dEz6lK|!wY9s8Jfzk_qB%w3^3 zRQs`)ev-<%52sbY?gZ->iS!^USviTJEl zwvxLZb7TIm03lCm0!0Q2%;f+#8aJ0}okwY5Y^4(1P&ySWo4+j+j`>cUEjT_TK`Z!ddD4%g9QX{v0+?>&4611 zHzO}aF0*pP!)yV**+5tnT-1^+xntQkq+EJ;`bU#$>7HA(T6G6@6t85TF1h?iH}*q= zPT1F)eb{z_A(Y#^-rcSaRp1)J1w>7uh2PcVO@$}I^Si#5$2F_QTt}#4u3=KCPPlzI z7=su zfEq$Bzmo8+MwWED%(+pc-qtS3)Jos`Hkoo$uMxajCGd2PS2D)hEna{d#Oq=?r`B2B z#$PZrxE28`Qoe4ikhJw6ka1$bTe4zsy3pghwPgI0|3*FftdSt;?=xZy+mvdYp+}h2d5H_wl$9c? zuQ_zVhkeb-sct!4Xc~)d(qO%?Kg^R*#+W3ef7Du$*C_4_ccELQymZF7Ef6q=00nih z1(Q{f1(WfKdsiVNNMZsLKW?WMfeR65lxyfk&36A0VfwZgKpWzN3(Mnaw3I)TfL_Xk z)4SGnvC%<&77tG;;Sh{tPASootT#5}(?x;q!szupvM3+w*-Ekkk&R?{y_ zLiph^RhS%_D?jE<{SH$9;Zg8hmekq`w#{Z%a7MfYp8$ofzV~YCdXs2R14z4wb&v13 zNkQQDCqMnF&ow6dClpk-1e7S}gyv(5qUR?^O5EOp1xIR0W61wZF;tvzKL`%mNx9Q< zAN=%konvM@PLIt)^}B9C>PMe+ZaqEk)@H5hmr+4X%cCNf4 zMYs4wdFg(gIN-3mOfLPQX7rfj_9W2FM!9AEY;$NjZp(A`e#A{2l+5m#fSx%zz~gji zwG`?ON7g&JU(rU+yc=n*AaI^~u+l2?K{n&VTOyUpJljNUJbo;=fjw?#v~%{A_=HSi z!=L&3kxl8~tg&csQ%&M!sIkNwIHjpCSx!KP1NYMai&;t8jgFv1be>kX_%a8vql4 z!&JzJ`7~6c1gx&;-Q(N0fCpu(=@GPRiP!@zKRq0jLbDef5&>@q5;p7F*H!TQz(8MD zDcE+WZP(qo`Y1CbXhdxFiK^BImdc9LpPrOX;U;r8_CM~P!8qA9Ln2tO+j%jzm$!?$ zF)>IX{{6r~`a82uOyC4mLS>0?qD#C0t5FC>aljG6ai=BC8w`Od^bCG1_-{)1YZ^To zl-#s>UJtH`tRm_~AFyS2FN!zAji%^y@vkjAZ1fve$We0IR(u(y{_fNTL*tsr&evp- zU9TxO>KVk%hno{Iv0>W>=IHfO?%}@1pfb~1YKB-vO}KWEU<^UEJ@3OxXYpTgb8B8H zXWw;X;g8c4-KrD5hg6sjF2u4vcdJPCHl(gqp<7(QmBsZ;^6+qP?i=+8(FpPlTshJp z9oq&pjRM}h;LY1jk&YD7pjz;e`D<3Knq77mY3O?rQ$SbLD^oeZ=w|Wa#%Rl{=d9i3 zcKa3k1g8zjOkS|IGll=;9#MmKVnAdp_}IE!#@NX!yy)3vBc!wUd_)SGSTqc0Ol9Iy zAFHxi@>uVfyGHE|6LX`}_S7J-S|wqwYfZm*iynbW}5kE;I5i!G~N@wih^{0LItC1ec#qiTDz}6X}>~o zu#=!F6VCAyaoKU-=Cye}7c1Q3trbO*5!#)ou$?}(x&9OA&XRBZLKy5CriANBy548& z+{Qqap`h>0_Be@YzW4x<{4k^m$ir(8*xYB%E53PMnljTWW>zk2o(_$9eif;+Jr7~> z94T-Zt4q$)kE4!I85=oOF0d7|@X;s0n!m@ZIu+DSSC{^n4ftqMS~xyiu-u<*mL&0x z6>E&&u@{)EO$1h}zboFpxXTf1%UGs#>HbbB4EgV8jZ|2qA7Wja`_XvI&Jj2iXX*>f zwhV^^s9G5A>k|7>#Z#gs;XxvlBqis702kL+4gB$`uR3ylq=Z)!0QGFES)}_9X%)U1mr2gZS(SV{8`HgQN0xJ&W zwehXR>*XJ)Mz)VI^*f_s&=J>KNqQB}Ze_{+w0(|Jpah;oh>Tg?``8-e50Ue!)e`HO zJcpr=d})dN)PKBar2d(haCjnx?@H9!0Gr!Pg=pm1zmgrl6hKLF?+n|f#b#;p-S3f$ zt4$2W{AmnRBE^zx#;&w499ITP!s45$09C-GQ64*- zb}qq^@X-yn4{S1hl_|Ih{vxRs zi?v@u>4T_DwCk)V^#a$)g4Sk;h>r-l5NDFmn&Cu>6w>+8bCav^{yPof!u{5Kt7lL5 zru~^B{t;jEe%ElMl2F-frWgmja54S(EpF8&p`1qOuBQLZ5QX1Ups@ugzJED%`yX84 zpDa?i5Cbk5S2PPDWS#uaf&1s$zgFBYAUcuna~@<*SmH@+7v+C$@1L!*;Q?L|?aUDs z5sQvN|MHM|q1x;^cAsze&}}8LXzDqdR>e2*6q8yeD!nxi6dKz`4@Fj>|Lm`PwYVQJ zj*;@u_xyR$pbQ6~R@2#PCDDdYtG)zzQtNlszN>ANQM++Kv1s_XIC+uIXR;SRFj+H4 z9m`6=M~Nl>Un2AaRzaFmvYQMhblBFMQpx2>tv(gxIId-yy~IQE0;v6?=_;L!ap|syb2i^gi-0>3bFO1rC4P?9S0NFJk-O<%*^D0_eJ=05O@hNro zy%z}m{P}Frt!1#~pV9pDq9Gej5e;F@Rm>WX$0!M44mExqU63w-N2QS7qGzRE<`FpE zT;#vx)2Dl87^TPNHcGfqqYX{Q5hD56b}J2dzT~Hi737L^iBI0IN11@@%BsBj0laGjL^}LeYWt#&X^68oC{Xf^gjuMpU>xPkNkw8)G2jJ;90bjWfUfe=n zH__;pEyxY;FTc_~L=bRF zKHedZTmpbb-iI=RU*NzVaKc3bgO*84aCD=6Cx0h*Dh%rDgK*B%#G-T)5bUNBtHt3W z$Ik<>iXZi_ZN>g0Mn~-O#T|TF&!EOm#9FP?KWNPw0=d2Xwuib4L`z0+z{haXR|qTt ztT0eth}k_%vgL@l?K}9Pv}$^Bqli^QMv_%r59V$6zKaza7xbB~f4ZzTSkbSx{{d++ zRo9v-;HD0M5pkK1Y47buzWNS3zH$5DJX?B1sTT)q3msTeq|zU6BpLG5_)1oifc^fT ztpEZ;QVvqnABwMhlpL@llp86>ym%)<0}(qd)lpq}d%k61zr%UfgOeeZ%Yo~7_Y(GM2q<8O&uX?ayrofy_7@yz& z`x~b5a$P>TNucVKBg_VlqgfzNr_i%+YI(@!f9h8Gz*XZfg!Ban?n6M%&u@Al)foW2 z86!b*jt4uCupaXZL79Z~N1}ry-&F%Ke<;cCmLkuGx#wEN zOQGj_M#ga0C_ASr{4iEKOufuxXRR~Qi!jmXMKYTiwzUdLsY}oeJ-5!-Ls7UQWuwkd z(O*|aaW;?`OL;81-`ay}Ny=bfW>1kz20G&1c`tQG2j(DMCANY-s zYX)W{@^|$5-^wnhfxKz^d|Xy!Lxw5#-yfLQY1{~58p`_*-XTnb*#1uCC7B)sFfci{AUGyUz-29K~6Z?U^?3v6Ykzp{5LEyh=e zY=#FGoQ#fYG?wS)J+~&x<(WGCCJ>NO7IkIaRCdfyK9&HBqtiU1OR@=cEX5dX^SSYW zQ6^bYxZLz_IhWnv5)`7ozA+fSxxufgDUYLVnCErXSy`-Fe}`vPXtqyILSoj&xXn+# zss*#{KP^VEvww5C?s&1I!U^1V zoj#vJIGz)f*hLuXU{;IDTPHzJn!q+|o*`uajS1>IaUrdm4;<@a&;M+m{)kYb;%H4Q zl59syU z0IX3%nqUu_;3iiTwAZOfFh732EHbb~B9UY^Hw@EmY zr~V69q>`D0gW%Korb4%y6T`7o7L<#?CUe+Jd)uKLU$1DG*Ga)??33eyTM0_rgNBn8Q~#Or!e7kx8h%em;sYE{Y_({q@GsLOK+vkMpbxo=2s2LkqWA z{EKyCABixxKHq<;WAQa3XgH>csvd33jx-HzoWD2T?xFa5H4Z@0!08USWjOt{H#IQ8 zul3+DuYn-ynA<_0L}xbF;WpJI`3Imr>CXX4i1N;7qcvEl~O?G6t0d}kw>-BXn z|0|RH@lfxD>p6bCrB-DOly4CDV&rk2#!54sx*j#aWu@KDt3$CPDh%e{qDLd3F4Ce^$q(0eRA)I+ zgEMxGBA7#yMiYa9)BxDFU+pzpi*<1Vp01&@nk@2xX5$Hr+Od?y!i1HO5Q~mcJ#}_H zP@dj^2{g$aBnjvqgc(SB!94<=kN$+ZSevfIUB46qTh*_vYX)u`ZJiPOigjmyR2FW7 zDjLIePSw5EmcZy~(}F8ih&oX!+!>J1%ujHO_$vDIoerr08Y`TQU+Ct~7TEs(Wg-8I zH|ClUqW?tq6FE|am6o$%_OUx}_$yt$U7jbsy0o%Rl?|iTz;TTue)r*_wi+A#Z4mk@ zaK-XS4Ks{D>c>L^fhHoyxU5HD*IVBC^i7u-NQYLCA04F;y?n ziTK=;RDVi361iM=Se811xDj&4GK?wnt!24+IC&jX?%oRZlI-;ldq@(naWu2pH^uUf97 z1vKy(2FK;*5NXHKRk8ej4RZ|vqHywLWOMqj_|25wu?C#!K`~|a@LECOv9_Qyn0Sx0 zEBKkx_kl;o!)tnq!Kpg=#0bQrA9>X?dkdMCsYniA2yT$VY`iNj`5CdS|Ls>6 zc6A6Ac*hdifO8i_Op8`(F#lt~q7btPG8SAK4UzSu_A|ab`gbjC(FpBQ2SDY|V8^@K z&Nt?c9F^;JdnN^V$fga52lBfq*2QgTpplPPbkRPv;G--@su0oF7?j;x%DD;$zF_O_f8teVk-ZehfOM=2xzt0`zc{< zUApw#@$zgFCu3-cxt$U?HzDY6FMtRFt^@_4dmZ(%_q2zLbun1<>XK2!B<_RvybkS4 zKR27DzZC0zgmohTO$a&Ng%782jkSa~pTBJF#a&xizrwBh4z2eyZN2+eDZ+DoDB8DQ ztxpU4vEklvON_Jw|Dk#={tIAs+^6lj#SrWig3&jl4a*v0kgV3<)lepK6A~KA`n?(G4 zXkF^|i4OweP+>r{9oewf${f$4Lzpy(SYhA0-nhzztiNM4{o|UWh;#MrRmi3lW^a_j zTBq^3!`n4WE8M^-nc@8AD9xYSW29H5I*pSmP@*bEFzA*eUpdknvr&4F_q8NT1-5>t z>K$Kxk(OEXkK*>f)5}Cy|Lmpila#N_21rEcO74ne0P7yeX-DJ7R1-{oGAdV4fO>t47XhSTL+51qZt?#=rXzhVM z?{+!16=wA$zhJo^-#^g zn~c||!R{HOs7HhA$J$wp-AbJ5b_JQWs^ed$v8P*su9mao83Fxig;`fZy~K3bq}fg7 z*|{lA;CAmQ;${agt3t2RYwE+D$q5l*%l+vVA?lCZWG{GpkH(r-BiD$>{ z&tLD3Tc6u5?i%Xhzcz~ssNU^ORvQp>Q!$VPkiHPv@%s!D!soovuXLV$u-}8@@AczH z&^*r(TU!D|7NJpJ2O>Q4(FzjtbDq}OK6yT-M zZLrVsKzLl2<@6?ZRgCz`F%nx1N{&Pfp+f_;M3D3x@Dr(drQiMBD+#DMWWmB;HtrDU zJJMk}2uNhqc6IVaYepD@N{2NgXuE@d3GIPeogh>XUlF@>Xc^Hrd=hjJt+p(TQX)~1r-?~p_VNw!Y*#$-IR zw)=|{+5fT%$sDNJoii3ts6pclU0*B?=tZYC1oLJD!D@Du-}@o*WjuKGlG%u@9iJ+$ z(18bk9D9%zH!|4KYzW(!U)t;PW8%;CrqrF{k_t{eDqJT3dUGjKO*(xz*&Hy^%RMzZ zK2RL{k>}5O>W}7sb@DUP83fxn67q5z^AM32lAJ{FV41Hwe$K~xq_56b96I%4aHF*A z94?(>1<4p(X&9(~jKN@0t;bb|91d+1&c}o?xolB~5*Z3awFMje)qY(PQLMWlGR^ZW zvET?;^sSHEkm;rksBJCDil~=1&7)2mJjm{vuj^G>XUE&h))@ldc#UVUlWe=DHq0H} zna^pj(xgzM22^IKpq4e5CXPPEdZw!yGBrL{68|1FfX#-yuK{ne5k$uQmVE@szJPG~ z!RWZ`GKYr>$8h_V+c2O7KxKQIA((3;@Ru3bUFxeI_7451xY4+zzcdYoL+PObqNm|h zaN;^C>ckXb01Y6!VE>M!SKPW#X9M0yvAY|zWB-sul>Sq1Lm|b90s8D}GMw!MNkmwG zc+3Vg0ZXyb_zrG(fyXWcYsT4)HaAOm+NB=;7$8*Lq;+sPI_u@YwRZNT+6aBkP_!czkf1h{?U3YMZ zFAcH3I>5t(?b8y5RBHh_(CX%go6I!udb;*SJ+E5}MW3scs3%t~`jF~m zq4K@fw-Mg)>knwmVM=&U)*A=5=BIV@kd;+$+)mHWM|LAFCwpk%0Xyy-2W5C^kMh7S zae+cQ?+0vXwi)(E`vhvemfX?Cm-MWG9->5mq$W_{1x>kQl1{u%m(cfGdW3R}U~S6i z5#Fmp`uqJfh5UtXVLsPrBVcqaI(p%Sd>+j8O$!h6G-&ez-P5ZeL#zTgxMr0oww&-G?`k>*--R-|IL^xKH3~(=3xfl;(G!As zG6IG7Vcw(gla3k`u$T$0t%uoU+Q2HKkfRu(8zyUJCd{|iAFdH++Q5BCB1qWE>rEYJ z4zOEaW&K+zB^vXBKlyrxWLJ4gS>Ti6C!{+Z_Q$+b!B&{`X=eT#4Ev)ctw&{h<*8`c z>#c_N!n7&o@S75{pAe}$aSzN>Mey<7f8hYRa*!(lyQ1?am%u~XY4=ip8I^hVoM5PM zm^-I-{*i|h0NG1e#C*+HXXmDI?Gcga(NfrT-_5uPDqE9$n=y(jdh>W>i)!liErQ?6 zU}X!taBU4Yc20#}u$xh4DB1vr^%vPJstVf4LSge5HrFZvXHZM*bnzeHj+fTEFTCNy z)-f)^x(g18P4%(SZi`H2H=DS}p?c?n(;CpkN9a1_6g8uTla1ADyd7}*!#xmpcjO@T zMCZp-Ha`@z_Nq3KzJ)oWcMjuyDmn5PQ+e6-t6uY|6YC#e{|RLF{=&ro9qGgN0VxjY z&cDG)y(dkjK*8N7R3BIVf&Jm4h&k^ zK?kbLR4t%&D*SfsH0F_`x*tV>iRJ~t=!;dC2Z&xv$2%8Wn*_HvCD?jrF-I4&0rl{E z9hlvTntrFkgdKoUy=NUsII2yy_eK`7mm;j`iHLhR-gcefTL^l=g;VXU7dE13pU7BfPnwvi=wk-de?U2SQ&JDdDatK%iV&La`e?>jc+hs7}6N`+CM5gy_e76 zEwbr(u1-jG)e8RKc13!K0k;)fH57xPcXR3(G0z2p??dDfl&oi-1WAb#3vvgWp$EaX zgi|0B(}D(E^Ro!`Hcp%IHti#DoC!}oiEXs~VVQr@1Y6~Tn{aUeSgJOPVzFa>oO*Ea z7zvmCuKp10rISN6Eha=0)ppX!(;MYecH&QQW^nRBG==6R1cW;-?44+HLR9Oqx~ec< zQjIqsPWa11a@0p7*}~wu31Yz=5+`UbZPdpsU7htn53~+NR8jn1I0%H@!eCPumJ74( z!0N&`lHDDG$1FJlsHLl@Iu?|0JPR7sS#Ak|+9;=Zv8LAER90*q3Ziof zKANyMwSiXQuoB_WAHbq`xM$;>gE>gOA*hRD_c!xa;poNz3ynN|@Zxp4_Fb^If5R|v zYLJOW1Dc=VMbZ4%W?ue)$uPiw``SxBts|jWM;cqU&N}SZuufw5)9a#DUr)B_tbfF1 zo?&S*(e4Uk*Q>P=)Eh3#A{3NzPp)$T06kPB=G#$M`v}f7@5cM?1{;DpBEkujJ-(@y z2vjFg0#4LRgF>_WcY=Z}@nY$Z^Uj_TIbdsVz@LG`-ex}wrF_|<&}vGtx9+2ZW>psg zT|=F*I8l-(zhu1;!r_ncYw}(e_fB4Y>NKjYWMLzyo==56h3OyOtx3HS-zG zbW{287Mjdax33np3F??4>q_g-Mw|X7nrnVM|$Hg+h>fnDnHI$!j>E1`p^?dEzKAD}$fq09`;k zZWb!;9dJ|!nHF*l#_xS0TKF?Y$FcQ(42HQxVchiU<;i=g&$vNVlm!{W+i1m`2dO~2 z^!$0%`pIm0JHOp#@;^IKG`D{yyy(q4qI_aLG)v_vV_5Gjg$wVZ_I}F96so_XyK-Cy zo-V?s)q<>LWZ>^j`gacQ$NV>0A%Yq7{X2O$3+4ex#Q%jzhWM*V*74ujK?jDgpDu!E z0!-AOv`m)di&c%&R*r9sGy!Ok{1h!ec2yFY5>W4Yaapkc-tqi89F}+CMdIU{tV1q- zf8AdMASnmjnkU^~%nJA&qUi1j6E>bpvgQ(YVUYlYnJ?~3SFWxk^WVSt;&_6h$%d=0 zaI4x#5cNN|@%F{4!l?k(?|WJAaSfRl=)?~EjK#c(H+$zh2O53J!;_aTiaP~}xFBgq z+5Y-(i_{lSivjH|Z^gy&HFOU6-~B!P|C>f&!MqsiCWT4k_IZc}!5SXnP{A3x&uTpy zMJTY8c6FuYX`aTyfBnjNX$DBO$KWShspd}&tP{!8W9nId$JDh+3~oTy3qPGmD}&8b z;OotkLt<@gQ(xUyn`3Cd&&+%&_lthsxl1Q0vM%zY#sA93p2o zRpQt$ymd?~g&EZdkWdT`&bW9}^|bme-KjwMRUr#hC3;Nq#?3@mx+~~!Sd|nl-#4_A z*9O!2y)W6+e}`TTZij^ON14ywG_9`1mphT%WhdFXV8u`2hP*LTIE*kecH?hti&wkD z5k<#UFJT;+F>6e%8@pRR4(t26SbqpFP-xs9w)$(J=#yUf+2#C%gAO8R0v*=@mtD&-- zcb!{PniewDm{Y@8K~EhmjL>2)#)0!sdK)jS@IpjgX_MJ^YArg3P{SE*z4fZ|ck{|ekoy18b=FZ)ef!^+9uQ>cl5Xh+=@5_>q`SMjQv{_! zx+SE$yE~-2ySw8#e$)HA_xXo4i#2m%pR@P==v_>F&AZ6LX;vrmxN3LAV^Zw{935k5UL9mP+@Bb*{0BJ(@eIX9O zn$tO;RVq|jxH@}&>n9F{(HR+)ErDmoxrWQ#HZvnMEHM5wsuzO2-zA~!xW_)0Z5C>H zytH`s^RxBcK685G>oP8+mdE>R*M8$6TvCSS3n0hCD&v*J)D@koM!6EhVr<3bu@Rxe zL16B@ASYgJ@gxhlHhR(iZUHM`v}kD{0IBb14pVW;xM+D)J%1c|hLMjTf?{qy zRS2kGg~cAu*UV+1^D8xFp8!2T-J*zglR&BY8X@zVqA1Kh29 zpOC%OQFSXeX}4RMQic%5Y?)`$MsK77psnUrHU!_8c4RuYmpKn_1O=FPk-4e6B#H%7 zU#1UkY)PThV$fxZ={-YtxxJr+PVbs$UIu9t9a%Gcd!rnOv_IWH^5z8+&O_1QgJ(Xv zyllp=s#}OQzkfxI(ht-3!(a7D9i;1R{ zf6IMptli|~bT0#cc@MO(!iJ2IDzM%nmlsE{^?L>N5FDa+2T{Sn$!D7(C1hJZ-u5`0vN0^Qe0dY5`(7J1l)B2cqlJRA)?F3nY=6R( z$n_k9QL>tSf2?9x!8_9XSyTVceENxr+R@8(g%m#xllD7Q!Sj>4^_jl?RuoWxx;8|Vu#_^Ig=OS}z=LIPDN1@XqupS9hTj=GCKeX zDvPlI7js{|Y&<4#{9(6X05{U=lAp$4?FMiQ;>5JFLp*r3ovZ-C*>_vRw;h#V>xlW# zQ>&88>NaBd#?2k6@nh+Z=4+XLdOy9nL< zFwFiHotmO(o+sZDlhN?`-rC<-!`Q)@J>+Hk%fb1^FPL=1$koRN&`m9Iw2Yf5g*bjP z5Ex~JnhIBLbl33)lQ#nPM$g4%kzQ<>lJjuf3AG|rH6F95vvu|jd49EgJM##{AcKXc z49bl=yKjRm%-%~DhRMS3ijA`k`U)&Lw8CLtc82P2_GfFIM}jhb%+tu?F@dI65VREY zr(*ETIT%T%{Q#nh;TfcESULCt=y_$}vfqq#^?o#Mv^%QZ*Q%>`Xy1nQi(JhZ*c_ea ze=cOzl9uJWly4Lmu0>{g%iekJTU+6B>cRD0aJ;}YeJ5w=NUX*yje(oPSm#3Bs!1J8 zijZnOp7WS_U~Il@nCx>DqW|@^_%yHadg#?X3Bowz7c zHmOIA>9{B;#Mk@09my@@F5In?YW%y;DZK|{%r0m!Bt*0IMs+G@ zmqdB#+zKh2wi?7O$J&KWRwpF;^#6d0wAcs|B#4B2)F0&Kb6M=%EL#T}Fml{r zhbrT?05tG>F4waF)h$eh4o8T#%y_pEDdiCi8rTdFG?xpWZcXvQtp3ojb#eX{vy!u& zzY6p!U0$`vZIsLPi%TfOS0h=arHq<3p&Bx_!i*=;pUow2hWtDX1;9P7WPS zbj6aL3)MD)$vsih+WC6qjpb(>eU$G}T8Q|hvH9EC*SQGz&?#}ZCJlp{p)>sVzQNKI zo>rB{oEFmCceF&WzIpih-@6?>GGrfWz~GVQc8wphL*i2>(MH<=GqbfNg(9L5o^9r& zs`U_gBCIU3OBqqD^i({ytZV0k-~xt4#~~eiXs!;k>{Wd=Y0p>gSUFvDC+w|{a!uMq zZ*@$=$0J||Qn*W4RNqD4s3*^}cT5VC=LKf#mRf4@Sc9`>EoaJ~a4$vrlQ>#tv*`dj z_uggn2WHM{ALr>dHoaGZ=luhz0B%<>ePm^+-JW+9tow$G&tg#iQ`P75+&q}{F<*p>2oDlPMBAK@ot=ZzqZ zjTGDwLZswj0j0juVx+ab0GcWv^`ZORI2H?^G4u0Wsw9+XpVfiSH?x1qrII8oDu4tMQe z%P4xl+@L_8juGBxGe3&_=^sfXesX?c8t~xv2LpF}aijj3+|Cwp`13V&W-!NN-LZm$ znVp3{hiVcy#lTGL7Alk{jX(!N^n#OnMQ6T5=Pfon*m&W*ayrO!eSqD1&ZL}Z^aeG6 zDE-}jc{SJ;=X9G322yAuj~JZSt})!2K-+mwdqTX*B6%pGoW#C41DqYr35 za7TbfWjq+65k4fJ#mr5AuZDna#g=BzERntfhhQB#v~!S_y^2@Ri(Q#x))pkDzcT~> zzDz4oDB`h10Vxq#+&bKbM-^8&Fu>Pj_6_W z*d2V}m-a2bzmIMpOM>O-X2y5%Y%TqYb@%m4KUq&0{v~?&hc@DP*bE4Ur5*i=Ug9>3 zx9QcT$?&k@s5O+K6%d_0Kr?wp;grvUKdcv;_3eaa{dgk0&U)d>+nRy2Ql3HeLUQF( z=s3_9q}5EnZgZg(bL+Cey$N%&%e}?IQ$N0wPGgDD2nw=Kb(hKQ6{}m(+|JD|L!?^B z7S+Q{RnFUQK4iwA_=7)#B$0}Ue{c=rF{pPFlw~0jy2#B6%mK=Qk+%AQ^CUcfH6i>~ zVHiLK;duVOK4sES3d|451SFXj^uUdQ$&$X!yZ7(Qd3`-Xq4YadqRqHipAdQc!3)m8 zU*HE=ts>6PJ6fA_`Vi_5>)C=>U6{JhsLWNO6lCIJ>yVb%rnoy(uzJ~I%XB?d0ykM{ z1>1)|aM^7*P{27@@v60VbUem>riAbGn{&kLrh$`<8zUuU!65*@wJ0?( z&`GlE)E<+P_1w4IIKV6OD?ND09WuLVS1r`_g##2zqYKBO9cZY;VkE^rKdJvdcAhaT zac>g_q6c>0Db7|4uK%?VdZE%`Qu5@Gd|^Q`JsJa&mXuDgz=D;(vtqWyz^>DJw?FX4-cqjIXRI~VwehkUY-pG!q9&$I=yy5@u81MxH zt|f9tMg1b1)=n824HNR~eTWT2*h4J}*fOe_z%tzsqr&$V0IHGmI2|x?F4WN0kUJ4N zQ4)Dfli~BfVwnelYj&zvfchMug>dF^cVRZ*Ly_{%7&QoYGJp98f#`fRZNOtb#MiF{ z=~FT_4$t~qtiIDS7Q-6yEp2pL3jQ*V$6d`4Plnc&1`KCtC!49gNzlL zTuyBM*GQdNxNQ50MH}AZbiKMD=+JCoasG6{pzEVq%d`C{b1F*BvcM@*9lg>5#fD}P z5m8)g9033MO8tc1e0kM&G1MaV;3s}{skFQ1;C}T;HvA2&y!c^$-hEV_x$v# z9?9K2+Tmb^34d7*3Efk&kz612gGcv4oOD4z#CIjYa*)`e4R1duDRC!u%Qh3fF_frW zDw(n0Y5h9L&=Ky{5r-CMl~u_399Q<^>XV?2?UBw_Nk$f98v7;IIs|On$=rTF-iNah zexqIjjIN{ldp@q*XVrW2BSKMN1svadx}w0z9L>`1#w{C(mF#DV*nT;(-Fn=@eqDd) z4@kBJRb2qSZ`Px*?2RUKHQ)-1KGfxT=~ooszadQ>7is#evL^OFeUx80G=|0$3f)GP zR~VQmrI3~cXAl;e6uy+u4%#QIFLn_+-icoDd^(mJdA*gn-Tw`^Zr(ZW(izx? zW~yEi$orNK#&A`@=NyJ-x7gO50|p@@7HuRCP$sn0(R4)dp!J{L0li(A?og?Q5i52OCA2U`UZp-}Q!xl-suHs)2wd5C_ zW5uQ6}Muv{aI+!^IPrrxRwBRZtNb8nfIwZ*e*GYKX<}htIiX-VQ7}xwBLR zU}*)nRre5hYi$iB8LoZ1-Q&;mR4Vx(<~+!=$>ya&WT_iB1POzXkX_5^eUi}wBdOwV ziEL_7w~1SVsHcLzxS|6zWBM<`%>O%XzBGOU<@zAsSCH&!ADF0UX@y|0mnE~-ASK}V zZ7OTH1Il!y`rs)Ji+FSX4DV?yL1PZ4t-}i;pJp{7V5oG5w4Py^D^P^D%mAX7UX1rG zG8{rTcLm|myacqw#UJYu;qSt0&9yzQK9tWRWRbA*wU%of$l(-{kNaK>{1qAg6~l~B z0%^n$L4$Hxsq6x*m{JAfOjF>AwxlHdI4%JHhD|43TdB%lhsaDZMJNoz?D z{-#tfrP`Omordzcw1OD2QMu5?|0pv-MyW`HqGc$a1ZeH~hQ~(r*o)%NThaW%`Q1W= zaU2lW8h4o})U4%}kTxX#?3#5@(hX1NoaZ8Fa#n&FMr)b{oy zSFLx598A4T%0=$n1wbpB^0nejmzC1SJi3eoxfy%`C>PopdWv~UhobBFUqfFpYIXW| z+>|8|&$Wuek_IB99@y=$h9Hx?>hA!LAhkUZpT(!2;`S0sRseAiBX)(};?oYmPB%U) zMR^fB*k%vcfFx=>^akqA+tjK30T4)$c3-L`fof2smt)Ax=a?9?-HJ?Tksa40e`a;` z80s-defGtt{EAMe%kFHGbDsQHO~J1>l*kqmiw>0WGDv6@*L`K7u7V;*Zfy~^1zHbQ z_jaz2=%I__=DYsaKLg1bLNBz)RoG+MD3Vb0Rxtcit|emM&?#$rhF;v~grg{0H8ka^ z8dcl0Y4jyAc=O1jyNtIE{Fn-bA^U!0249wa>se%Y(VHQfPOa1!Q)x0Q6DK~xGH#XM zz#%iW2nB?m3L!sgnJzW{(HuKYp|_eY>)iU_2lMsEirvTNhsIpf?~X}gWHnzHhc``E z@7$3e^;w`Q$FKKgLt3FTKqQ07vn+}q>lL~~ap<`nRMp=v;#3T>O}mR=xyzpA2~-;n zcwfmMjh8*Yb@e;F>Puj$Nl;%d;bS_z1%hS@frw8^PxG})v?%6)%et;QA?rF(s5nBJ z3}AZtD!0RFc&hcvHyIlUL``pH!g(oalpic(i*FOdjU(L3Rh_>N#+AH)A*Mu6{nywR z0J3&)D#O-H4;U9Qur{xd!Hk(@aTd#;YzGf$0XikOE6$AvSS=Nw?oqvd-b`s6R(j{$-uKLe;IoTf`e&#O@x~wtVlvg;6|DsK! zOv?rt-g3)%&zYGjb7GYFdoqA5ML>=xV3cm{>IaEF&nFqZ2IoabayG>4K&!H!8?5=`eRf(&gr+==F!2w*$OX8K+~(7_Ux z&ZKrm*olgtp`xfv z2T$9p#>NEx;-!Alp=FO`M{tFSw#0$T-a)|MwXVOGby0Ze#}PBIk&KBP(6`=&)-G3% zelvhSCo;bS<@o_o;=3$m?z>;hdY@WQw@ek_l$|+ae-g1 zYoiShjvM4ig3zZgiRt~~J*ee=pT5MCG_WyPFF{fWu%Lpie^@n%^1+}hy!Q?e6N$&> zstufxufM2r%P}8q#O}8mCpTq(^|NX^c0B4X?aFa_kxt6fW&EMStNei0tB5MRaF;InV`RSNAW<<1m>dY;ndMF6(60|Ua=86t9Cj8 z!XM$>3Ddu);vm4F{Lc}G$H_fc3QmCcr0?CQB*ULtQ)$nsxg&7y&rW-MR& zrd=0^$+$gwemb++X?vwX>d;eSgsXzv;I6wn^JUZ9y%TRf@Sf9om~gDplm^WnG%x@z z>52P1n&_=0@$KF`zE%WmSbDCKGngQ4V=>`=^D~##YK#CQU(YeQV^K3NZis;NOh73&e;lQ3JPa+n~+n0OMQC-h2-=K?`>^M zZg^*{8^T)|U@Cm*Ova>^*Vr0<>`3`5fBEN~`n~{VeGLw~I`SqE*cAA(GGGXc5m?&z zQX73_Pn&A}$q&b*Mos&f8NoUou|66hHY4Q&6G&Ud^sg}nTR?6(hgm7vNO(_^^$;!T z6gXK2rc}zj?tumQKKeqp2&1s#2+0$*T$ctQFu4}yM&Ltjp<{gOtJEJ~5Od)tUIFMP z13aof^gj`i=~1fz##bV_ar0Ji^TOkIE4$jeMC3XDTm`7mGFFcn0gbVLgBU*0QQ}1J zcmk63Td`EoWW_c6R%iWXJz^zJqoIn)z$;==~EVEVS9<`^^^)6_D0sGv@dKj5e7*-A*S*eYL@vY z>qRsam$=^P#l0?W-tsTon9`hhdaw_4SNRW00SKsRa0lJu!c~6}qfNiq9fx;97$`mk zU75;BoGU9}1P!MuW{AHdwIV(KN;Ljge*lpqypD6_0WP6whud;PO7>CE4Bp=*62FqS zcJR==KOEAbd`JCfgmPt4W6wzGn?DVkXvm>#l(zdr|3|{h6D?L z#bOY|{e5cveKs?or;FV0F2$KYCb&gvQgaO0fHVQJA+>U|U+$*YBb-_K@IKEpmOaqc zpDSPFHuTlh&r#S%peYF# zpON^FYb5rE{q(x9P*p$6AWy#BWYr^2{xZ;~N4Z%8rfxl~0g65?#*a>&^;<&Ah`0ns zERrB(IPa3GUFQ}f>HTp_=vbDm=WL6$ws^<{S9Jt77*6o-I;?+21MKjNF#zLfBxq7< z)s(bRQfI$$z3d$gi)0lxz1Gvj9}OhpUB*(qwp>l^1}p(gn6T^7r?`!rJ0ydR9r)A- zy{<0<#@Zg1V{_H+z0qOO0MSV7&YMFV;CPbbbMxvtX$!l3{>&|rRDCGjluCFl7c`?AC*|+F8aWeDYg~ zP|G^GNMYHTAuQLn5FDI$q8uI$T=&miQOY%uims@9l1Hmm@|`lqZmPtb>6 zC%Ozc++I<-u)gDJM+>ez$;~(UY1;{Q;Yio33C7x`lTz+L$?}-};(hc;Hn0tC%`Nku zeNzS~>#lW@9G+8zY$J@_Q4HQ*viCfHZsY$Xkbn>3IFP<2{t^jK!u6APNVt8Y#QeQy zh6B)&Hbj0v)_Nj@>#ey`--?Q8U}I1aD1m3!`0^p>+ZPO)fh22(^T84T-?$k%UH^WS z;am^4Q~cMN`N%@jWX3kB7eWU3Q#w^IUL}s z!RK}c;FQkaoRFO&nzg-k@2!U~*H>c=)Wu?)7u@S`}a`3|2IcTd~g%kR<@jY39R zPWWB32cFkLS%4nkvn%f70YI^^?=xW|&9s(#O5^M!{x25jYc7wO=;`zC$RRz`>eelk z$ovyBGP_|;w`ZGiB=5fVMTa}b03g=LILBt^g((%FWzo1>twal|=kZ>^=#fhS;9Zjb z&Hel-HkZV{Vtr`v7AHug9+U$jiH(;>@{= zT?Hh{(xYP9Ii69Hwi&?F(~C{L+`G*Hh@J&K3yQxm6t`>Ve11&Yj*h0PWqNhX?io3&4KdR*jg)kxv{mHb5;dy`jfN?TWyf#<(# zEs?JPeDb)T@ns7B@nMDzdVt3QjEh_h)d!)if?6A(`bag8p{dHMP#>C*P*IB6>VOF& zl;|}eL^7!0@KDQCuJ8`UBbHW+j9fB?)ep=Q{s$FO2?Am&SC#>TX^G7bT%0TYsEA3Y z7BmhWSgmtXPNlhpOKP=JuiKHdIq&7^Xufh;3rsSPf>bKxAa(Fthm-V5%f+#nwt=VE zp``59AuJvZslX@k+~*WtcNr2=62;25g^(Td>;u-?M|Dk?Tjp1zB0nSE3G9n3UT&ea{(j-(W!YpRaI_dw6RY zg|jW&;T>aD(quXe;8*4S1Y*8iM{Yk435w+Y?r22_n4z{3?&$U?GWa;zP}2chDrS*d z-)NgZ1Nm1M&t=ZJygnrNBG!@fP(H)>(8$jh)2e{X z`~X0?$<}G}lb7>X5uOk%buf1kJ^Qg8&XL4zT&>fm4D|h}7Os&&vqMWWXg6mPA#WWM z+ztpYdfqd1%Cs-Ee*+k&e$p=nxK}aYQ9!BD=>C4v@rS>UKeWV)OmH&uiC5?~O{2dS zfT$G&sat=J(hUYT`jtw-u^U~8qaBlrg{edb;>B_)7>z`*7zfWY^+$tO`oa$9VKT$2 zR4ly#4c)CzT{*XJg+^Vo_sxN1f{Er-^@M`OlD55JWf;~#;)80+oMX0C)7{wu0P@9> z%$88h0!WlDMP~pp&`;L((qgZ0V0$cAmU8*xQR3IQ<8{A0##WKP(VfL^OyW}>A@Z)) z7xRdvGQYowh4a;)?8kUYyhw6BX@&4rnQGik>9+4z#eQs8N3?Zc;f1cyw~e(=gR@T# zQZPXBT%YY4<9!G>2Cy$1k*^Lds+ZR_LccqXOJ7PaP`G>+oXOXy%h%8@ZfuQy`NtU2 zsGhxP@nngH_5&KZ6)N(tSNftU8D<&gbq4({f3FtILW0~1kGWe!_pa=`o`A}SNUnp< zluIs=pVPsuR3(a)x_ZsEv71W}*X9qKIHIiWMPY9=!rb=h=g)4W{UJMI==a_1=gQ`^ z80K&vse<~Phh$1II-&6oOi?a2fFgD|DZ35+K6}Uv7;=1Ke`>*wZ#JV*Pvpd>ls6IJt)EBvd*;^O5GFy~Sns zh&i3I-PVQwh@?5UY0i~uN)$pjAEoe6J%v}*p;=<3Elk4+4O zy(n>g>O@1;awehb9T1n^S-sriM8N}{y8q&Yny+CAdTQlfGd8#}Di+I6ZnT-NHC?-7 zw}Ie~%IH)WWsB)GMTy+3=BpHbjb1zmLQ+c+eT7x&8Pf*+ z{Lh>Y2m|uQ>&tQ8O|u&{tpQH}ebk~C0~ShJmFqbIUHU^N8(<3qQ(W>c&q zMf-ZkQR^rC_QERDMIoRBL<#|&ib~k~bp`=#PiW20q!QH?K4$H` zqD=FmrgY4M)APA_s{Py$U#AVKT&&vPKf6JbO>p4?Lapnw!;4$G+YByQ8AukluLQ~J zu9g}WH$yp=BMB8X%PD^1vUjzIX9T~- z$Xf#|)7))30PU8{vx{|`F2+z1f&?+p0N^`6cG=-v_zEnp;!bec#}4j6aP+SuZNFA; zv2Kq2u7;&02!_@HN4$t#UR&n&`uQJjs5sHYuX^s-uvK@O zrAhhmu`UrY(or_L1n33d(3Bw}ABI?T7(Ek8sl_gfg*1UZG9_3N*{wlU9?4jbZ(@yj z&=nE~tHKMUF7>Sgot95`?F;1w!xpjab^EvL+w@<}LokjUW*!I9bm0m+-e_?8%gmpF zeHw?_wkWrQuz47*uNk6;@d<>Fco_Xlw=F|VXt38izuGuBD5Z_OxNB{4c9$VzXAc>P zyKNAAI`gRNaX_ubhWuIolIY2M)vKE!NBW zi_!gsHmz)4|L)H%fmZI{G}q)*e*jBZt{sH`7A*g>RQ`{@^h~}HC;@7f616X<$c;LV zen%Aj8xJ6oMg>@FJMy(+*?rvo?|7?1)<}w;AHNyKMigBp^%p#qa=Z{z$TEeVE@2K)}zCh6D`zSl$MwY@;|K zLI1P-C|bUSY82Phz>XCGkG;^X6?J7_2snMm#2p_pG_KR^dVV%n-CcPDNO&wTnDGXEW? z!OGS^oHpQtVl%J55B0q`xXc4YKgP|K8Ju@1oEH}-%n8td=Q76b%a`Uw0kH1Q-u8{O z+{hm_9rKmAQm3fM!Gx~zhn`R?=??P0dVb$bc;kQjz;`Z-!{U_uG5_N%OXbsJ3!r9^ z?^awA6P+`Z*k@kS;*~8GcTV>2(<%A&^vr(t-^W>&e3!}Y{5)3^8F*%IirzcnGPqxb&$5>I*V;WKQVa z4nu3m05%H+{(5&+Rio>9pYt*@d)&{TKLJ}ekv*<#o$`I%8HNRuy~tvmwyR>Q%b963 zGJPxqf{xY-kIRniSoNZC&TxwJBI#obp2605**IF1Ox#DHnq3%4M`38c(y5-)t z?&#;bKDB0j2v^Tp83C{RKrMW<)G`jU5$o<1+}%FEPDBFb+(-nmf8QPeH0;0#arav2 z!Q2MuYb(qYj8+HO)E_bfVyNw<8&wzF=8MXm4%Jkv%)Y(87p4&r$BCl0x~fa(G;?g%f?T{CCyiAJmG}2+k10|iqZUz za}KUs3C1vzT~Yb~IVlPPsyP}kmL)g)u^I!CEpZq?*AcAexEIG>y5NigD{XYw;MN86@c=`s*+5c`nrE?;q9^zm^{80RUk zMK%ySV|Z&F^yL2;k?nR-%QJMqKgGsH=I;oVP1mobj%wmq!0HjT(fRm!wgI{I#}_)p zR>~Aip|~YzXz1)<1aXE;Dul7DAP^*p$_or=7Eb5`j%b*rk5?fk0tdOn9;!(-P-zn ztgPc}xx+5%qwlo>fSklreKmXzR?Qv-k@$?linWShG<B!i`S!Qx#>FWIqoCTiNE`u%Z_om`L>Mda&gr! zy$Z9bLPKu2N75Bmm(dryOGOp%I>hmxVu6+$*ZMvdW~)KuvsJj``QcSG1i6(X3{F6h zhG={XkpCurKv~brO^yBZ5-T20n9%@;MkaYvx;0)UO5M7ad)%xN36?@3E#u{X1Paqt z_^^LKq#H^Owcw|DKJg2dZmx&(MJ-vkkpJrW&Jh0IY`u0*b_M7eiNL;koxWVdA1f-$ zN8Pj(gwPrvhIRwrwvYHW7H`_Rlk<<9eA;j@{^wY|qU5dq;#;H>Z(~Tg=bh`e zc|pOkA3vk3&*eVn0&n>l5M50;PSW;1FWMMC-h5ngR~F6d;y!Ms1c=?}5A&a66$L+1Na`1PHsrUoOIr<`Z6CQ@Lly!-68TK&joKE-<6HKy(TO^eq({t(!M$`7}J zA@qU#Lz68+3nnv{H%l3Y^7?Rnoz!uED*C%vc;buR^C7i(9e>9i0H83h^Pn<8f@uDlbvAZe*nDEkFvoNncv@$DIYDATh3!rYdv_KLmdbsD^H|% zyn=uAs=A&nJY2bezU8@EiQVd9ppk&huC_1abc!isR(sx}^q%#dzqr!*`2bNIgLdq% z0C8P~@z9pxKx}WFz41^FK-OdxP?Ude_mqR8cf4fi;qNDYH0PKDg1H-uUQAH9C~n>b z%0&~c^1NIwIxQckv~7ly`3(JZdlP4Ww0&EiDrWNZC|MVcjq(%?n_b;N^O_;#x2lBR zWq3V22M`Pl)&gu%ad4>5w};pSe*k?geL2z}+LCd`bNfF$W+Nd9rlwImQQcpQJx+Rc z29-#^Fl`TChdvgYug1SNzwdSkKNOsAISAqau6un75*^<=!toa6RvfPsvMN27v@rr*=` ze6I!S>tHDF^~1T{+KnyJ93orEDI64Z-MsmV=V9WH<>nnBZ1Rt1JZ) zk2P8HoBi?t%gl75)EBmkKH-tWdNJmMntosN;h2|>NtJTtv#b4ff322mc!`BaxPfI97l`3iH>rn!NJOHjbfz>NN*b?h0|106v z&w~<6?v)nG-UZjo$)hc}o3Du({)MlhYYGEjL{0*>0-0B{*A{t>IM4<*e!=OD^?$yJ$Pn!3>Yp-je~ zQ+8lWI*GN`Yj^=WCz>~NykKd6dfDlFIL}#7Uwj!mkxsw?Mgi{+h!_C=JMSkr<0bV> z*9NDiI`q2z`Xu#Py04wxV0LAh(qO4Gm-k{+*ys)`?DF!G$+P83&H1s}nXY^HhA+e- z^$P#(4k7)Q{eFY&E(L#;S_<6qjCx1!p~Cz?CKAp{f!y(oZ$HZj#tsN*umddTYb?i) zzq>f)s`|Q{zw{Fa=6bnSVo%G|Gxd;mP=9?$HEAr?GXamue1mL7!f2rn_(;D$Ce8Bx zw8``S>QG+dnW$a#9}UB?3ZHrCfQ3WpR)+h>rF|M-vG7i=$_nEVahXTSEKlJRfXM4U zL}4&QG!Jt0;k$SEVRWc5c94;uLx9Yz{u-~`HKNTA5wAxnQ-r!l`lptD{%lm&OUDDx zK?VZS=6hl_9n!frCk7j714h-MQ?J597m+P#6_facFQ0a;zl(YrJEig3i~1}5eEDq+ z&h7@CN=}a1xLyH@#2zw^YdAag3Q1qHq=l8!9Q*U*js4z46OD5540G93p{ij{JTW(D zRwL{%Ic$0f^8WB1h#Gt!9H-5`^e(pN`Bp+L;OqYJ#j>#1^P{urjCgME-gT0M3tR05x1_s2j)oIwYz`$IvqsP~o{Y{}a*BqT>7sR#bIoKqts z(^A>h{FEPal`1~`waW3EI~xAKOyhN&^*9Y)nitPbX+h_AeHAJSuWPA5>RQ1 zo^;%srf7XS1c|2e1yo2S7pb!+z2%ttNP{j%aMKpyf`n0papKPdOcW`c2`am*jtYHa zpacZSm#HPSyduTRyM0NAj~smE*7YU(Od_rr=tb44JJX)}`HPMdX*7WDx z{}IZZQ9u(ElB?AOYozVLzsVriD%H_(dP1eJCD?RDkef?t{^Q*MI|V7In<}>Hwk6My zQ}@%<(GS&%YQR-eJBc&t32d?ZPVuhFjBT*kZj*3q7iQD)bH?+Q8cT0t`{(w>A~kMp za^wWv%>jN3?l@U00pAAY7hTx^AA=5=|DlxVMWs9xg_1BGr<6MG?V@vaxUGJVS?h!Q zegt;7`{lhc{9|fRde9^!BxGfn9M`$sacUDqG~A_2p_ex{n?wbR*h@&>Q`26Zb_WKJ zPE150Z94U;sN)twYR~(NDbuobnDH->s-}cGzleuk&&4I+UOhI6P))-TKiOolTV|?rbxV%nTcHHRe*D>D!cB{IfML~Q-?;! zGR3D}`nNT?=_R8u6;3mxTxXqki?c&^yr9~_xh2}k%~cWuD;xjlg_q=4Vp1A_`3zM( zO{~UYa(&d2qJ@vciB`2VWHWTsW_v@!eD_s0iBUHh5&x==ddK6jo2>}mfije@`aD-Q ziKOe8fw*Fec2r0HhY{7#C}H~d=LjqBr!SiWl{%LN%mycL)kAO&3;LqrQ7EKh`^a}F zZ>tUi8?UVhS-u@jE{rCmWx`8GywpsoGRysP=$&oT4v$x+|y#zH54d z+6=96OWFsjH0Q1)e*$%X(%s`1IQE0uyC0y;deeQw7UQQ!*gcmf_HXWwQ)I5~NnxmL zu0ce?Ac({1$`j^tZ!6Ox+yXlFFLwrqZ1GQic~$<$^S#AwF{Q-*aO$7mxr?m2O}xTQ zf0xs8cP1I#b@Ox&1w9_9US*++NiG0}yKi~i!n5ZsWCq~#j;2=+DHwy9j)?(Sy~Uko zW;fqo_vNX^)W&$mZj^3^xaDKdHX3+r&%n_ zWW>#AKLLv42~IVZ`|Rh(M=bR>kY+4xX`z3bmw?1;mN7*53-4!c*C|t~pE;K5wl!~s zf>&E56n~(^Xwa!&9oQ-6zL|Oc#9rL|K^xNBP!uU6fPJE)trE`I7xlim)NZ!+G3oow$TPsS_{FvK!W!Hwa3%Q4}7$BsH%@%Zk+--O5RsmnHeSdzN42dqDC?J!f^#ubVx`0?`Jm1lL zcd04q;kJkHXMK^@_duXfWqM+!ZBM0F;PnrMQt*W7VooUQw1C)GOa>8dO7Eu!qdX@A znAO*XMpt1n9d9qSb&U@QuljP0E}0k@WGk4llwJ#WBQw)`-x{WVbbnw%^9i3SYu*98 zt`9#Bt<)mi4~gZ&U2-MqhD=`0CmR zsn=|-(XgQMqqzZ5#^vt3G7GmhV?k3!`W2w$mK|lp=;*bHQIVGRkIJrq+Djs+$IK^U zS~ff=p}aiLaE*eW(Xt5^DZm=O+poQ@@KAgJB}DDTqy_8x+*Zj zoa#crq*u$Fm6Dcj+ckmXcGbo3bt)gQusc|uv@Nb)M@EfbI_#gBbX}17$54?PKqWMJwH3?M=58-pb-H43X> zp>N*nASF?)Z{f*(WUrV8s&bb*hEu4XGgT__6mB(p^857G&^e5Dbh1}Y@`q#`z1sec zL!+PI&P&yIWo-943Kl(ebD!tj5Mk@aR-OL#y~e)3UpfJ560`7?JO2hG&1~sAgTxrNYhB- z4R(l(4Iu;mzf5LH9|&SeKfo>o4*sXo@)2zWCIm4(_wlec%4@v8|NGk)(8VDDon-kJ z-!y-hfB$#t-{R;z1N`Vj9@0Zuo z(%L;Jc5V3WRL;>aytKMTit-j0D2QU_IEMHCuoYUH7{I8g?LMPT&+O-~{y4_3)3<8U z`S^gntfUXOfSc^??VV_L)(Zb)i8-?M1zhblz;{hewK^YJjhwsw`)s`QV4w$>!+HU%t*yP+NuxsT*1Uc{<|8kiDSx z&v7zn=cD23i8$!5Und(O41y(C+_d8V7=baNR?#O6 z69rpbj*iN~OZ$_Ih3yQ2?a)`v|9E$5b74-xOSm7PJY-4FxBi*UFJKn5S}ngw)R@js z9hPwl{PUju`5OIk^)?J3z#ZGsYTe-d?H%~%qi=&?t0klm?SU(YN1aW`Zx8+rv(-pU(&YU@Foe~$UjJO(bb2Gu4Bk+?>FRp+;>{^w&WFKw&ODDT78 z+0;M(`)5SZ(|uSVtc~#$?2|s{=DN7LzV8l6Afwue6%i2uAxMesk^axAkuGrdGRsY% zcVIxBhwa72?k+h9Hep59AOITf^A7s~+Ud#31Tr!j`j;S3T+oRPJTkK6Q-ksE)9>#) zmm|VQ$dV8M`4U=N6P}JCLpzhO)}rBJnw9(Nv0P7_gE`w>`Mhw*G)CaZk&TeMa=JbL z`RPA%5tv&}zUZ2UhzWd4e9dpk2i2jth$+(jL()504G@VLHx3WY%RjXX39~i?jrXJK z_u2oCkq}>oq{ajbfkCRgpoJAuE<8V}8xT_SP@X{_{6O>n`T-UsHM8Mh&$R45l ztGFh$6vadTdUL=33S1*l4if;5IQPs20uvV+?0OP_|6Cc$4}@j?EmK-n}LZUCklWZQQ@YgWj!>zU75p%>i*5M{QX*1 z)QI{Zh-DcVDhfSJdM&4w-)Hk;Ln#4Bs+r%v_U{x)eo4kf6fnn|kr$8ivC!rHw)5Gt zQV5K`-tSAqzi*`teMFYwHWM!m3D1HD=P}=|`u^nqWA7`&s%pEf1xW!x3F#0eq@=s0 zL%K`Ycaop0RHy>b>Vyw&js2ZXzo%LE`0f97M+8W z?ZL2qNe2_bKmlznmIVE|K#6Bv@}FP!vZV?8D{|0z)^hZe~ z!O9A^B4_?`U=Hf7;Zgs@rl0y<<_qh4dsk^fkns`mMZ@MXVY6MIMpqEdCXh}y^r?OC zU*B`MywXP_A|k4{T5p)$+ux^&F65&9hDs0yM8l`z7O0x((%#c6QzHjbN`$UE9PjT8hoNY z=qiI$=_qZ)6VECvl!}Q>18J~9Qg7PnkIb-1p(zmwcKVZ@MX@|Qu54$Xp}4Z6l1&y* zi<(TDQ|NUg$7YJ?mKuYCFLuZVvjjRn9JhJa4(0%nMSrD~de71$6?VgF>WehdD~(@A z&f4*uE(NBG4Q)I0B`j~zFoC!kK)d4h+TIaq4i@(^)|D1`KZ~7wNq8#~LmLm2L6Rz1 z79&G1ulu5@LKo_sG|d;Aj2pXihN~lPVPEw2qIYkc?nKt?y9)gGuKm|eZwU`I+=2YF zeVj^mysSt^W}@PV)OP3cRSong@IcT+D=K_mcFW4l-MfEOMAnlsns0H7?CqkIt*Gjk zCvvW<(5QD6gAOIMc9PWKd`U1z*J?5XnhbbvMUaqnhZ;poWzjULeY{Nv2m}DXOK|4!o#_=wv)j*(R}#6zA^3X zUSFbC){BapLxOAPmY~}MkJtG4)WzDa?6QYm@|TT9dO9m#uE2K|V%OJof#$J-+5g!& z{&|6tD?|9HFv$4)F&$Gv{PtmrB6$FDZ>ylB!pAbH8m3v*j@s*M4t-Y#jBkl{E7`++ zqjq16o2aXs+xvI#oP&u$@aZIxJtjS5fIDzYKAum$Jh^SbNP?ooX4&Eg?$u3+j|AIZ*n=Dm$dw{)pk?*l`!*8X{pM!mJFfn*{DV3t6C14x!=LU*s;OGLj4 z+TQ40udu$-Wp}^Lv%|>^#bMNs5RWE`-k)bNCN`1^(xcUEN}E>}%Op<}U;Wt$1NFLa z)vZ_|zu*TlbND@Xoi>ZPhM@_nYIl^|ZxW{lF`Fx^1qZnjSJ=BeqnzgSR3W6Tp2@=4 zV!`bGLW`dG%3M%?&Y4`L{c}p$HK_W6i+VeVFnUxu!R2z~%^}@;%!fuEZ$HOSpf*lC zU7{ImPm$9;>6j6MV+b`^(%`xoVLHz9aH|&_FaDjFJO?F%+32#0ORhSh=)tCV_5rk> zBPZPI-g1AOY2-$B(JTTGF15iOV0i?7&Z)``-dD$+90%A~Ms zzWyAqBepV{=ZW}&(P8J>k8-5R;?SJEkl7K<^Fvr`8fZ9N{(S#V9XyuwaXXVt_73iI zKRW^G?u##ysN5QzFft!QEQ`~9(}Y8k>IX2`CeCJa&jKuIV00@$N3qI{EtFSPJfr*s z+ehnOxJ{HFn3>D$B%jm8(rPkITb<{tjNVk6kB~akNetR06WHv{$W|`%ILa#wLr(j^ z0Nul2w$kMr%wmInmwNh7QeeI8Cn(y^+bZ$}GAK`#zFH9MjnJR4O1(6)EQx|E0Z>Kh z=Zvx!-+UkwW?5g`+Xo#>j7GLLdeP;oX6}x4>c27f*a%4{2OR$_7Yd9Hi)9ww+T5gR zv^Qfsl-gm~+!*aPiCc-mysgY>Cs~1;Cg5ZNx0zbxD;39V3?+-$LuO=ExR~ClyuhN) zSVv}TBVJ(a^1LXD3u$vM9jumLSsJDLGngb!hh9SDCfU98Elu#HPSfoa@2bPk2}lCTT3*YaS)rYKLKI#8Jx6sNh#dk|>pGM>i4)e0_7w{l!ud z%wSJMw1E`%S*0qc{;jiPt%p$9whZ|MJM`tL3`G|dCCAboRi$7}%5Uf!ebrTOCJ0Xha;A0IV>77MANzo}#(-Yr3CBOO=R;#4NS#{tTD9?IX~JIip`V9AB|rm+ zJ#}5zWNbD)%`4433)6o7CDY?_PHCa>NPgION?LO;<3o{GEhqmc7`v{Z`!1Nq5vUgP z>tm`#OnJB+wCT zIcRdmjGiZa#t|XmBLL4VYA1{&%zHh9?%b?@%_9VRU8J{9B!3K)Rob`z2obz45#G@f zXL%uj`rd)&R3_w(=#>%LtMFia!%#4olZ!r8S&?Ubx2-}ygYBa54}_1`fvw;RgY}Wb z1?OLWV}1_bKYKV=KWSf&;!%w5I>QP|@HILYZE1qtW9`1imlz|Rhmnsc(m|81vxDU1 z5078wZ<}qC#+5sc;?IL2y}=M!iMj1b$Xnu#0+KWZ$x8jORlU?UpMi7~k2~5rtlf8- z4H%eF)_df+1_Y~j-4jKZEEsXZN)rq0@}_OXNrB*^hZELh_es9oUspJ+g~K$sLFL*z z`xb+{{Co&hjYH6_z`ZYFYm351$tLwEuGq$7|)q~7?`9L`Ss0vgbYWVZR z$V66)PY`IR7Zdo8CQ8KX?|~Y!f!gaFoX*-W#!f-AvwaGN!$~2dC^^jOFHuckHhUwd zB`MpZ7@2O~ujnP^;aSowpynj0%3l<%zu2{AS zA;!eT)$J-5sqDa4S5b*u&v9&)?sW;Be&&ew=U7M+-;cg%jC?y_ebB%ckF^nOVZ(ws zkU-{_7FJ#4Iw5xoUtJ@uhoTULhLKW(O5Azj%r+$WoD3VRJ1?s#M<^8659Ze^!v3n; z*<(3dQW!Q{>ld65xAv1lJje!3l+A9pj>%~Y_NIN!^&pekctj?&tNiO7Yjf{h$Tc$o zhdm|?0~$4l)ms@rNsu;PPAd*!p;P}>?|M4^10I(lm6mhjMTHhAW3M7-`kCJd8iEZb znm|`%t8{K-{`8LkJ%pOHFLun`e#FQLrGjbQM|D|EH6HeTv^|QV=$%roG-)ODw9n=TBl@lR(KKKl&~>Hv0Fm(pn1&R_M~PY+WP+@EW4+xn%oPmg zNL9RnA8+47B2vHWIQu@?V;LO4k^ORfJ4v%tDcP^;p$4+u3KwIuWKC|}*Xg9%EANC&`FR6R{)H@>EC!KuvI1Lh7*sk(rNl-yj1nd~fI zc7N3LWHBKV)t9e3#|KLNVI-09yS~qS+%*4E63+=XjB_vziA*%t=Y7qhQg)IoD{7ql zcvrZaIawUL^{UV|oq)%7gi9^8ECL5NM_YBUPyA?7v7yLMjX&=E>txyOErUwppkB6k z=nJKTpD*-FaCb?IH5(VGl|w02LQpQWo7K!1xd+rRQB)-n@V^*4-uR{ADqRT}MChgU z+}CCCh$x|#XjhxqN}L8#m-a;yRcgNd`1^Z4uR@ln)jSIqzf^v$Gb)q(^P{;00RxM` z{Scbs!$m7DSE;{8{yXZ#vN!@11wnl9IiODR=iM(3R3_r!{D9KBUi(mt`_4MC{G z8LnPC_MnO;0Y>OPP~IQkoC!^!G^L>3XVXN6jkl7l-mR`?JHeDk#vRWynKsr@q73YQ zpFzOz5W6!b8!L2pY3(pub@W*t0w<9Qen&cI6-Vf|0vD5_U2W~}Yhs2s@tUDqm{U&D zN*@O3sZ>Pnj>8bQ7YCUxjmNAGtDnrbLDdX4ZPsYA)GDKPF&o@#GXYuYzbw{hQGo`0 zjdq!L<9>{I-MI{6GzzFuA=t&D*(PwDiOd_J?WunB$YF9TiEhd(bR($*%;_b`o^2fx z5%Y%J4B4BCbNM&iQ#ZRy$n)+TwmQV=A5baey~U(bjE<&?nW04*fBl{aU@mIM1moR* zG=QzDky~{BoRCJ~ZES?FMlb~koX2iDS&BHeir^H~mK*oGE`9&Vn$w{DUm)<)3P2VB zTuVablfwQR<%DzCKv~8fo|W}I{2Lt^xeA|;EJ5__bLVD>8?!kyu+@gp)xu$ViKpX6 z#`86mfGNh(-isG6BAjq%@|RcgvAyuSZ3whUM;HyyF)G)TD!1qo7U5s+Mc3Qp_JX;u zXOyG_n=^VNyLyml=6WS?xda4hQUPN|@myss*0#5mvb^b@$7@11QY&!4VMyUa44*@P z$K_NsQ9M7hpsjG1WI0=}7f7vo8))ZT6x#Z$u0*R*x5B*a`i)wimc_RzRRPaVcUZf!lIGi8t`75qrfMecYHDmBJsKGUE;<>=)+7Zw%u)5<&V)kHh*Hk;>9(m+pw9{Py@@gULMOZ~5k5 zi+e|aSPY5;qhdsAaj#s*5ticc{ZNE>1F<`)BUWrK?!Nb>&$S^n##7Y4>iU%$Tv zLY*%-nUIL6wZkD|z)+VO8{LP$7rFo7&)f*3&JZR71I=3?uSDysvw#+d6jd=^mnUHV z^Pg(;zkdC%OB;fXz(*6PMfh=PWTiE+FIMOW)FGQT^L^L+!Fj%jIFCn&Wuk<4a@J4rg(H}{X7d;NROLx#c~cW>j=!-1nh*a_ za9#A@r{d$du)TO^JnPgwR5VSfHiL8K`c4jlWV|H}`s7&L~#RsET$GDB6x z==(X2u4crOD7Gi`5r$|uGRY0t#nJJ5ES%rRW~A|kw?BWL(rciOo~Ao8b8ACjoSa=C znYHnLSS4O*Jw2BxM5TehiJursiZF8+IWA%l-A*1UQ9>`o!m@>0LSl%8b;Xb$NERZbl|5< zGP$F*i`)*EI1@Ll4;m`2w$ZFl0oDiRP_>8%Bsy!-W}^|971n1Qs^z;5@hANP0K+{G zG>9Aaiv$aB4FKc_#IqHKpKXbZ-PV+~J;+13wH9|i;s?^4 z%(@jso%QoK4MOCV3U@+^5v@Ha4UCPAC6-_NM$bDJ(iW*@(L`gWWlDa3f6ricjX&SQ z<#Z4k%5$%PMXN;y^yiEPj0)o15IC4kFSDFNc2s{o_>-H&Pxr_qFdMdjdcsDhP*c(l zDdi30PYecCiP6cWqRH`i^*Of^EkqLb!t=)s`y~jp>E{!9rX|TFlirRS-s^USVlI!+ zY3Z3N6{?rEAm44+oE!(zwUh^s(+R@uJlw-Gc&wH(tTht7b4cNuqTCvdN42*-7?a{? znh+BX!6nspV|+WuUUIHnq@dbDKrbFv&AhSx`CTI%`$(ALxpnSP7mTWgqj@y|oZ&5B zA;tD7Ylnt0=o3}hBXUt&n7W=6^Nd~QlNq#D9+Au(?f*X1?;TS-?o?jxbGz8AKHJ>o z370x)`zAPHn19PB%h?*Xs>zl{i0T_ z8n;G1Jlv;z1(KWEf~vJd{|32(jr?;w31HnBReypdQGYC}-CDw>8SFGr=O00(OdHSS z)KFzUKE(pZ)i&+We2ucXzjWBsEy!EBPo-2;=M-wC2?4+4Y_?0XXqr_w7}g}dbgpWd zG9y1m{QG*&3V8Nh;0Q#kx(me)xa_evbfGiDLPY}_OVJDSWZ2dYR`8O*BiY@D(g~(J zV>Nd9(Z1mN%;T*y$!vu_<2*O><#9M1%lY1w`dp1MW#Ai{uuwnu4>*hl0Jr@@bh4X} zwHu(oEx{xdaLG+Jm8j%LBym{@m@mI%C^bv1I&8W+j!zQ|J79z#H?8KS2+4Q`iCAThzR>mVxSLvO>rJ1#y6)UWF4Fa`TVf*j-z|0l`=eGKOHEgj zE5^ISky)DaG1h0hiaX;Mnl`Rq1ERCOWOhCJDvULQ4f7T912CvnL{~U%XAECsJ1TJ4 zJIcn;YG$+re3sIIA^+LlfZ8+^MHzW{b+u|7bhLWy|_|V_&Qfw2PCgG*B2BDFL%P927OpZR(%2)R>)k zhq%>tZ0(o~G;1Bw0-kFT=B4%#vz3N(+5*CEyaKH)4`D>YZsbHLS3hb{S$uf$Dcb#B z#?Ks#2E%e900H97P<-{d_#w|>+`u=h zbq@x9e?;`IgiJi6ux)^mz4ly=_ceol?} zktvd)nJpTgu~t0GJDw{Q4iNbIGQOT{j&%mg0oH!#uK8Iw^hTJ>Kj_`&6!=%3qd6cRl+#*ma!2gVEeI?-2%BP;Wc zC<*}9(Hn%~mGt4-y(4#4`=PwMaHpEJ#{xXvGnmLaVb;{N%=>{DbKXr@SlEcKN2IB_ ziP^GJ(1$~FaQfT&*|OWV*_Hl*DIyAD_@g-J{ub60N5}E=_E5a>!I!Cl9bEiVmRT_& zW>Md?kqt5Q0gO*Dg(1JDGxP{(F-%a$F7OVWWMsnX-HTFayMms*yRO5ul>iFWnTrB> zEj1;t@bOLOzm*!pWYw51y}NX#w(>x%Eah((J|3Lb?(0N)Bl*m3r!+9z*=~DQzGmpp z=N_R+yu}p>YW;M}VLDz@T>uE>Hfs4=87B;uMD;-&lYpb)X&OE0qXNytFGu!zQiy zJ=%l>`SgE>r858=ZnClp>rRHs#e4J$p0YLU9AZ@zw*`k~w+gp;r8`*89+00xp2{dF zcA{|k2dGw|NJSOS4V$qL&TS>uBWT(LfmTI+uxuY7N=?yHsujicVpOoez`-S$Vt{&0 z7kV5G3b4qGW^`^|mg~LFhvF!Ng(Doj zp*3#~Ivc&eF5}3F7gj<-MXjCm3fSk_zGD!nta47+G3|j#1bR0kBCFo1gi=f`G@Jz{ ztVU}yCS*W=TUydGZ~)LQjaK)?^V_aqNLRDW>RU4T0eAftU?5dAyRNYl4PCqOA+Y!J zPO~LSSl-rgy5GHbp`d1M)z&oB-&{64DEbKe5txTHJVrd?i}N8jCae}qQN{^vK6@zy z39G-)SeF5Z9ro(FQ=!>M0(2s)^3+2;t*{6@>Rv3`;5h{#mn-Q}lzJ|hsf%xOu!r;L zgwZrtuNUMtQ}(6Z+38cRKgn-vf#;m+wWcicEn$c@m%mAJw~0C50fH@DY<9!*Our%3 z=8#JJ^8uXReC97jG4kL6;0zTiLJnmHE5$=d7!l)nL-uzksS?ay8!KrF`k|{yH>XVM zo|K39ACh`Y_k>(&G5RDigZ3n^uE^ylE*ISo6Mvu`%-`Qz5}Mx6)=t}c@ktmY9~e{* zBp_}Uw0&?m_;nU8V}aO~Gjo8Rl8SsI+H!YJm9N=Y;(C6iJk~VJXf4rNQsj40tNj2q zc2mp>x;W4z8>x2Pw7^{$$MKuumnJ+qiHjbCCSpwyFiJOSc55RRXt9}akXBA!5c49MeF;joL z2^EvXujnDoO~A^}dS^@sT)BTVlJ3Dg6RBA=$Cqb(vSX+{W3oUj0k0|+XX4{$%sQA* z{ZT&FG?~rG8}}mua(b&_irEKFTeX-i!9)wsuA(GQd+Ov*kK7Khn<8O+Pi8ISlV1qgF^BsB#_54^v==zU&3Q3iO+ z2d0&=m>j01vz=aKX5_r=vQMR83IPLjYuV?nj@lKV5JE@b{$W<{?=C!hf19Lrc336d z^G@0S8X-YXDpH~;=wS*F;=N2e(O(Mx;;XwlHEm*=QXY)M&(}0OguBa;PAj8tu;2i_*k+RFVTy51?@;xm7E{^PRBHLWycyiO z@CP01%-r*d7>v@)E~#u2umfOG?;Oj_67SGqpsp`mx+mTrpB+UHs5125IcA*eg}zuO{U?K2m&V{J z;0h>AZC?Uc9fR{l@ zP5RJi2T^ygrDiYnr$q)6s9zSXS3mJXJXHg+iceFv<5#etbs+8!i$ORo&*6|63UyY& zNZa_FSVlvMS=A07&w-%Oc*L}^*r=wG9)AQv+K)u#MbZe%j}LJR-hV8WCR6eRW7fz> zy6#4a<>Z9iF^3Jp)>4iefP+&K0Ra{n`a%V7*Q`yDUKrMf`(wVcUcAJidDQgCw}y$v z4;3MXKO}8YYQ0@!L|?Jl#F>u^&u0GZ(?+Ie3OEIg(w;yfgq%x>5ObK$r`~RsGh;9i z0V>CVxU)bw-zLxl?+qvwOV04`NxIhr=5K)I7g{io*f8BpUgD?5qEaxQz!DvoD8Pam zaQrqca>kEm>%Kx1ccRdE7bl$##(2%72lr_7**8Tb%98cu{qAa6o9-5^P&*ClOBJ`( zSIkBwy9(6ZrVK$)ZEwMSiFfQX+Xary2g~K66?gUL!><&6VwCnP({|TQ1N($Ti}t8Z z7{PkMmuSY*FOx{tc1e}{J#+jcz_k#6$#d77Y5n{dXXEH~*s?1dVQy_=TkFSqpQhenQYkDp7M|$jkcvb&;DVp*4k+LGzKP#+%0RVkSWqG!J zcqcEO%Fcfj!z_>q_7p3yVZR$WiGKEsfkx~Tzrr843jDJrD$++{Th!+IID6%$%e#va zf+MAWUBiFTL_`rEsj~vim^Vf8wJiV*s8gf-aSb}}!Su#(yHo_H>7)xB1DTcouEl?+ z@63i?$k=S66(E0Ha0W-vdKS6KRLq0hl@z{+73&lC4IH5+<25wP!JiPCrZNGm==k;| zr#+Q4CijXIfEvU8ikqD``)51m=B#0=LklCJy7tZlKQLJ-lh2L-9n4ti!w<)#PQj<{ zK$Eo z_@Sg$?VlVUM*xYsS%s;=U_9MmLhZ+!uAoGUdh5*yvB+Er2#Xo)bSjHm$UYZ@aEngk zgSH#DKwp&G$X*~gNeTXJmpN?7ZJAN8%dvRswBCT>%Nj;J&&ivesXM!)-$6J1zkm~+ z!KRBTU#7fbC&wn%eCz(p(IhMB0E_av8vubEPtCg(_xEo<+^99QPK}@A9tw2^M4Oft zlLN?njD<+hYtRRjt4nl%zw^QJd}e)e;|_`_VP)bt8eH6dCHmjf{;$a+$_j1uK$a?w z5gs0%Z<}35x1J9b@-KOKjg$lquYDErl~LR!;GXStvK7fM$P)udTzjeLYGWnd(Dkj5 zv}bTk;`02{G)`=oa1k_`aW!^$=jA=eW5m`foqWx3+3v+)`b)=ny2S_ZP8-{U{4*(< zR_5Gk`FB!eK;%sX^o|(eX%t`Pu@DDRyN&RIQ1Q~~#>ApTbLXMGSw>x!CbQPb4@eSJa-$UJ16#Z zk2VIjdyeE~`pJ+z`eC<=-fW3CgC#*YjD6!$DL`ux_b^mmM{Qla!$+z76I%H7l`4nB z6r#5lD)v(2mQgz0_3ynk5OfXH`&38=3hAuU;E{e z-UgtWtZ=_0I*x!-EYWTx>!F>k1B~=)?1MEXbkLy5gaWXl0W^qFP((-XASvGZ>i9jN zVQ&DcCjE~%$>LOnzQhLLMP8wQLI%_)zQM6(Knpyo>@8aEjM$H)mmK;_E9zP`#pO$w;TV^ zXQNNBn@nB{Ic+aq=r7SZFvKa9s!;+mIL4Cl;EUhs9@P+0N{zbjQB)6Mrt>vIZ{NNJ zg5V^%ayiV|YMXB`@bDsyx9gJy{fDi^lNY;mj9<;8T0V#JC`mQhNg4tDyCOORv9J$~ z$d4Zt5dU+26B8gfHuiH%Co*(u`T@xaR_uCrh*%aJL6ILHirT1d=SG~tOH~y9N7D!h zdnag_*X2DmwIo0{Gq+#A0tC99!^6WI8qb9sc5jGf*0&*s0etWcx%Pd_CY1SH>M`*2HGC?$^q6DX;3oR}bp;;D3kF*mcUi zXJd*m#%wkxiOW0LQG+CZXuUmTrnT<&m5UjsBGnbzOl))F8a{mm`L$FPU*v z6blrhzY&%YGv<5_9(@3m@lt+R40ZVG{;#v~S&x|id`y~%b%Rm#4syJwhx{l%K+(I* z8M{+DebWP~t#OZ%oZ7gz{duxJe)(EP-62Gbq5fCCJD-7wmcH7{k|)QedGUroz6aMU zl_rrj(OD4TWxC&xB~6AYW}$Go0q6}oOSj7pTdIlGHjH9lrimrQ9xNSBeV_y6ScX1c z223$?QT?qS~X-Q z=NM2H{Xq5WV0(#oyg7VmJ(oC+{wD-XVHpd^4SRa=uwTD^dw0`J3Iv`Jgr%({I1Heu zRI(t(YNN8Oo4C&6xe5)JzPy%;L$gM@vxbm~Cm5 zjAu;z5xLF-;~&Po!6ppRfbo<;?LYSGV%)e$<>a zHY+a%eUl^wnUwz--;MbIs--o@SXrWORY6OVdLRBeX;UaHP$wHWk3Q?GU(!Cqd;~7C z0Qq?vag*@xUd3lGZX(Ab^qS76MU<2^g4@#SeCtyG9`qf&hpNpd!B9W%YK9qdNq;Kf zGp1Q#fg+J?`(OC;qE3&$5OrMJ_q1Z<1>X-d2H#8jCrUBEE|(Po1j+g91BFk%UHb|U zKAA1Oc=>0={jcx-C48zfOXP5P`UkvhX@P4`x4q~2eg5}a%3rZ+0U{u#pFY}8lf&rz>YpRv>{RQN`qcmMJ&wTlL%1h? z9;g}aB77u{;uvar@zmRvcuP(OYHbh)!!|KoUZIHZVY@Pdg8E(td^$^s+wa?y0DSyf!Z9y&4E{lBQF4iMfov{bYbsvIKo7+B_SZaS z)Dl=8h|?!N=8M+&yP6ks>Xr2j1_Km8c`M4220A5bD?7#Mcw>BWL11I8^W^nThP#4X zNt?}6L#FE00qa}EgQ|2QKEz_aXPLX0ZXlzp{GlD2+pfqT$GDXBrWeQ=K?~U1>((49 ztcxmuuEBV;qWSjYE)~1`o>7KyJiQ*7@%hid;~&rUJNv12`^nfYfqF`n79e0qgZk+U zzxbLNE#=ey4DbIsiXvbExzzFR(}*4z$u|;x6yb^+MfH976}(u5!A_3Cn5{L-L)(bx zzfVpg2}>_9K~lx4%^K49ydUmWpEI$YrU5o!B>*TPkt0bMTPE%FA0g|1uo7dkusYAM zsV%YM$;PsYrphgofcU#|Y|>qX^7m3{Q3kO3fW(08j!6x$4(pzpttrOKZkN!^Hl6+U z&gC56n!P4^+0^jpse{OvChXEvhG9BnXCYe|IdG=JGX&o%g&nkvxI3R^%ZDI8R={;! zr{GrQx6v1`F3>Kpx$N@*SXm)u!iqLDUHi4PP*fV;neu+hU;b^JuToy%dUQoBAKJal zTWAYNUy4*(dM0-GTLH_i82Mc39)NQS!n1AF+jwl+GH65peyWZsUdVPFh7{EBy+mVS;Y>-@yJ#f3>xgB z&mMLtw2DU;Bv_>%$gGUES2$0WT3?@v-Lwzft5xqxEV;sV%+IS!C$W)%m1v^d?c=}b z6S<0}n2%|=<6k6)Gz(N6(W!kDDbWgcyB($NdGo|t7kwMMB7R?l2jhXy8?k*Sc3(ah z3dzq+jRgc;3{c^KFs3hN&_j$eS$s181hNK!7;-X!`8+|RI-z>~S=CODo!{q!o}p{K z`JnI#Fd=_y$mD6Q^Poj3mlaoaIHGuLywYL9R%4eKB3HW<`T8|JHJC}q_WoAYslrO$ zc(%aDE^fbEJi1$w1+~Ieh6pj9J7m3z!1Q7x3(j~1m&IB5uy@)#RJ2U%&2&fRWB^vP zw${PKVpD3Py}4rKnVihw_N2LmI24MxDvDQ1EN3&BDl=R4YU%Q3Z8a4vRC%n{0WE-h zRJ>#i`3T66?A`z#Z)EfSPl(adJmtMU=_B}m;@GFIW_ddfngq-Woa&?Ss2H@vD9&yy zsH)121?C;4Q@F^?wD#TseV+ZpNA)-w(v5mK8a2Qf}RQVN)fCwh@v_z~ohe+QHrB<2^CzF>3-LHbxw`A6HQy7^&(Ofxf zDV(>$_usiyfTvkd4x*UiWqLl%Rl4NvEw_p=rk^KLlildOf&ovjDn=5VE&d+1^~jsO zo4#I#{n`MuK%i~CeWTM?VE5hraEYYSP`ZZT+sdfR9WNG4pmZ{q`EvEfu=dE#B@zY& zwMfV<-oDBcK#I(dYQ8mS0bH0ig`z4oYp#|yVn$8s%{6`l#EZ_rt&WjqEA9{9BUvrH zKEeB*?=R{DngZxJKl>Z|FpRSPB*2!kDv90ZgW5-g?h?)B0m(*d4PEzjKVCqkfPYa7 z=PZN4kqW1#i-fT1mU7W=tJ-?cny>vpnXhmq>y%}}{8&zwO1z)Q*O3^U86ofb_Wl5< zDC;5}>)ZeaZ39(oH*bAg`geDz@`C}Z#?#k+kICua!uO?O_JVju0d5M%Y81j>9OC#L7{ zov}71G$c$D9b%@9wmZ62@~;-^?e_~VcLTJI>R4g4&-Z3=_Su>ckdOk)QSfLr8_>)e z6=CLv=>)6xOSIDbMkXlN2Qf+_vc35GXBvs`TDe^YbCu6H;6eqp|&>E_ScN!L2GMN61R;S(p&fhNj!{D^Tn;r zsD`4QH(nGLL>7pMC}N`!HV8frR~(BUDn`Dr83~ALfBvGj*gS$+abWgpss<1u{JKJs zN`w3w6(p;(+num7J{~}tB60nX&%nPo8DiMK^tRRqDJfd7X@?kPUvo;sd@cGRqkB`v ziwc~U@&$_?9%AUoKLd2Y)6}(^WDW;612#95b_ijh-Zcx(E@yAdhS%d^^tM~4l=XC< zTRM_b(rgA!KN38I>?i6aee<41KuFgL-$O5dAw#O(SKxuM{%&z4H(r_<%>1$XJ8cEY2>55ZSIPYj{X!%he^Y}uI^Lug(F2XwYu=5*Da!)WYF(3ZQybJrBfvl zMXA2j#KIhOKkqa7vrGUxM@SU~Dnkx6s$7fgk{%$yV^FGTC=*i=?k~K+Bnp3|z>k+@ z?2B#$t|dU72?W~9@)LdIAuN&UH0Ae0#jVIfLnzFT7d%ISt#fHwnx-ZS-3MR`hVi8` z{ARaeQfey;XhV+oPdRINMZFSL@RRxE3#WSe#$K{lycansYk{H5k3ONCtb&xWk5Y+IysvP+zeEEi6Ho?d5} zH*DtaK?fUU2uhuSe*~&%VhtVA3t`eaZ~et`S+>00-ZUGN6N&47JJSCk&{pg`Da|c3PUaD`bPGH+p9_j zz3Wdqr+tu7r7!IPDo{{R28wj2{t1E}Me1e@ey{P+Uc6{{4^YG353`u1kC*NST0G~q zk(xOFiyDquueg&vP!6+#^-SQ}uuv{q?}w`^PN%O%5A4RfcsoTPREnd~ zJpdfui|=yQrytLLM?QOZ@$v*W^)YmrtJ$ZfQLAB{_xAQ4Fflm8C$#ad z^)G&TMnH91UU{gtFyhOG_%vC&gE0v}_y1}=>Eh-rpqz#h@0P(JW@IG|gcQ)hf+dO4 zAI=!-`|WFgG*zrF=fqxnfmT~v?K&4N3A~OtmJ+LAjg<9;8Sl%cL!gopu3l^2rAFGr zK@OgJhJx>$-@j?ZPYUKGyt}Iu_X~>O$S^>jrK7U&Ku&!ESqO85_8&$Y(;W=wutTOY z1KPikEq{+lCl5l@lPF$+&I#6RvgBDJ{p|0Fvim!U(}8SBPjt`gqg0Pwm=K0?qx)UL ziq8`?7AU(3O#VdK}iB{ToVGYlc&jQS^`;SJ%7K{BOQ~bt2EYx>w7;7D(t#_w zBflmNU2;zJ6pG#t6>Ma2h=ccZ?w|P6kK{)}`OiU;XFif7pJ@n_lu!U_IPm#G2hZuh zi?M;Qdc_=QChsZZi)Hz8GJ(6L1&3LX{LDuH@VW@5*P;G{v+)n0z2q-Hii7s*GFu~~ zvP*-JG?@br#dkcfuAya}#oQad&w(p%m2Y|UN8z=SXyyOEgr;te??yu4i>j~ZgRwRJEL?p2d1vQgG|?+d zg~x3mz~Dw6 z(Df%m`gnU`mR=aB2(zfYfEE;CHx13!*Wi`VZh#KL94vY=&>r{+E|!0%Lug>r)Gabcl3lw{x~Iy14ta>=22mnh&t3B5O?&%zP0 zjagpBhC5{U{-LsXe5^o!+k9NK3Ze|eQzJh#vd||m)yLIN|m?pph zsOy{C+uMOY11tQl#V4Oe$sE-EX`xoBQ{cI~l>my+je(hmC4<~9 z&F{_Tn{6FXI8rhPfmYTN`RcqWA|kxh+AX&X7Htu~@U8;>y%qoKVOyfU_(;65CPe^{ zD5$lXWD-{52YE#g?24LjyDGXEp!D>u%TdYq$E>Hy_8~A6xr^9KgsVw?K+% zXgzFcsxX6KRbHI$6JPE259?pnYR`t0$fQTOa^AYAR@g?n9!=J6IqseQ{v9@?+0eJ( z6gberd86yuwmS?4%bs37SziDfSsTF9BXa+^1HF0xQl$DE zG?jD}K_V!u&g;nIwndl23nr}q`@OswaK_mmo#b9m%Nb^lL`2Vxy9XRj7mJ9$?E?gR zsp~VM%hX<7#wFLQ6Fudko3iCeH(l)#je0XUz%@NaJi0LMLgzRNCxTQ&`b?X8vyazT zaI=0pvEMf}2OBkL(3!WaRPzSN1HWhh&iAI)b1hf)Sv!Wir?ba$-O2;>CD(&V?18So zSJC220+EG|Xdqms+Y3%WdjSFHkleJs@jEx^17|Ja9fv>SHPzZf}TS170`{50p7L&;KVB%*ulq;33q2%|E1+Zq9^B#B~zc@Fb zhhbDe^oM>(sa>=ZO=|2~=V7e#8E%~0BlQ{}J5%v~PNA?k-7|M*_o&%9p%+Qxe=n*1 zL9Qz9bZ=A&izb2YZi&dqTM9wR?evJe!f<$b3@D+iHW_)jGM&ovFS}eE02OU+^J~CS zwF%Kx!6~c2NwZw;J-gGIFL9kdGuQGz`PbEAxJ*Vs%QW+{=9-ia`(fskJjzF9K&tz3 z_^DH4ETW9v-b`=O?)o~FB9WU$2qE_e&Bi8bL+R8ALhcL(N8R~1^KQCC-b#R{aB$mY zd8U4kNc%g{!)?W8xPwBo#5bpIvozRv(BwYwC}9VS9R2Or_e|iWpFt>xX6s#28+Z3^ zo6Q%_5|M@})#j{SnI2O`fV$OeXSuX=Ac37`%3Zz2M9-VSOpP@bC`ge3Cei3Yv+fH7 zoJ|yfo80KiN-mjawnYg*xS*M{tAvA@@m79(w6)-QaiDNXL!fgne%>^>=@sin~i1O6k6|2i1|o-Tu0TAN5)92A&4m3`2`E`}8x+t$vLjlS>W)f{rhf!tQpJcp^0UvWRV(7wl}lAI z*Xw2u>H%kYli!(p%MYPIqd*Pepi8w~uuiYZ8@i;}Xy;_Wo~L(Dl@UN^I4|~0v`sHm z|3QZC1&9JcZGcdqM*>%;-u|or@RfL9drC?{A&NF5=m~k)Uvw#&)+d1fEiy_9WdOHI zq^qay+U1tp zE8F1u&79M%08Ha0Z7orcxbqv^-)+f_QELyNk&@c#S z#C(r0)N6m(t6yxoRTU=Qcj!^xqb%vi+Dh}7*mnL7--#f)Bi?W6CN#EMN*=>aWHA#z z5^)M*OR&>A_+rDy^RtTN@WWi0yP#ULvmGRxePzd0lMAhu^$mjALLGgvYGsa-_JUTU zy;Oh&SD>a~IfNplpjvqE<=p#WtAo_-4ZaQSLGU>dN7Zby^@gmriG3O}fioX2`&z)1 zdV~9L+>vC%##n!18RgF`KvR&-Y|%V<<_ZyR1cz+vPD_HR)vEGlS20e4%T3N)O6xN- zPmb(|s~d-s?XM-#S3cE^;=Xb}WqCXaLTHB)- zVsF6;bZeYHvutdTCrU{gV!!a-`mVLN(co}fM}|G;cEP>OdI<0%wjMsagVH&3Q)MlZQs2^}rPmE-HSjM*^)jw;Lb#$exQB}sE!Rh@2}c8^~kIk57pP6saj zW3c}@>Rt~>P+l^0{rKEQ=ZhAtryc8|%)_+WHPpe4H$%45buNiF{V}wIBDQd>wd%Yz zy`0W((=HEimL&+B;D>jXd6@4`_G`y+3{%chTDXg+J!Y2sV`-#Hn~tqHAOnY|YP!NN zv0nCdci0aNMr*5Ayz30fV%wd#kars|ETwf^c3GoXSP#9+caqwB8<1(;9Be<0Ka7IU zlm{_;Ua9S?1DPs@IPdu^895}6I^^DL3+=~v3=ccmPYp2H?M9uR%8$G7MC)q8Z)PeL zk5(E$j+WeO3-PAi@9cP`YqwJ5zY*Af!o7=396#zNNQ~L6hFsx1hkq$f*L*o$MfuIW zoXYfDi`#gE!;-Q62LKRitqnCNgcvV1+|Rtn6xmv%(A(33ux|}}WV4rGHwU#`6_1Z^ zDhC`(dzWMjWeSA@7hs4G()qgDc6E$Z6 zHzVuhc&F~+a_t*u=llA4sma;lA@S}_JqxQ2Gn@5LpwYxj?$ffW=_MBn`&{uxa0)Y6 znByo*K9NB3mC2{fEyEK%BK@kyAz1c_OWT$MKx=LE?0!WMHFt&py|Exe)gHev@RbcG z&jqr{;zJkUOA`5+z1Ye8V1a$71O2lxuFJ*FI5~mGPqD#u_2W#_{K^b9)*>R&5)s*EK4nQg*gA6E(+M07 z*0ToM*9~!cN}DZVL9C8Y>C6($yP214Pt2q;cQLQ9wfEoxE%XCl@hi+!;mWh3Ui1IY zO`_P7K%kl0Y_F(px37Op=#BOm6MRVKXCxccgkR&Y*Ebiawud;)KkIq8i&Wx~woLBK zfrXierBZHX8V;^gw}i*ErQK>E`EHC|Od!3nhad& z8?0;-ZXxjFC5}cY^!vKA zl6UX&x3%1xX(V^wO{{m(`~CSzQTu8lgSVT$fB!r=T2SP!)w5$;Dn2fHwsYh5UeAwf zO9WROjnX-5z23}x*X;H2`|YmB&vJ{qnkjd7uX}85?5ruyn{v0mo!opz{BrlshZQop zHA?c0d;W@-n;#eb{r&xXxBCUTp9P)Ucs$eR*5>hjN;9inVD^2doI1G3hLs{~ofBry zExYsa?%Kyer(#_HILh;ODSN!Ie8m6DVwR|F(XQ{CJCEC27bHY&ElS;-y!iQVyLG=e zT5HVG$iK7Wqw>@q*#Kd+d-L7m>wW)y+fAz+ATCX3sycL_i=KQTa zz)em2O66r`Wiy@2GS_;)>3cc9{H2TXyLrl0Z(JgT4xVC{ef#Rz#lu&B{&#zG>!szR zSyivEitGz4_P%a%hW$yx^6L4kuB9I>J^Es&T%dhbtZVY?cgkhLU(K$+TVFUExh`Va z#>d!r;o8PN`CnS!?*He0Ib(f|X>Hzz2PGF=@y zvu=ofd2#k~*Ol-oD28$ftnfd;xA51sBR#N64_=74veulA2#h<*39Sv`5??tvT3$s9 z8!I7)IH=kb5f$JNeHuCk%?gEp`3(*$_L&+gBdS)2VGe=7vVPPGcsPy*6iU%LnxaOt j9=OOD%@+faFMjYJn{s4gnX*&>0}yz+`njxgN@xNA%I@Hm literal 0 HcmV?d00001 diff --git a/docs/images/providers/vercel-token-form.png b/docs/images/providers/vercel-token-form.png new file mode 100644 index 0000000000000000000000000000000000000000..991b9ddedc3cb3553d763ebb0c9f7c9ae29f98a7 GIT binary patch literal 91853 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

Z^?P9D*6it*DMPK%hAtU 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 literal 0 HcmV?d00001 diff --git a/docs/user-guide/providers/vercel/getting-started-vercel.mdx b/docs/user-guide/providers/vercel/getting-started-vercel.mdx index 67d4853d18..ddec26e6dc 100644 --- a/docs/user-guide/providers/vercel/getting-started-vercel.mdx +++ b/docs/user-guide/providers/vercel/getting-started-vercel.mdx @@ -13,9 +13,63 @@ Set up authentication for Vercel with the [Vercel Authentication](/user-guide/pr - Create a Vercel API Token with access to the target team - Identify the Team ID (optional, required to scope the scan to a single team) + + + Onboard Vercel using Prowler Cloud + + + Onboard Vercel using Prowler CLI + + + +## Prowler Cloud + + + +### Step 1: Add the Provider + +1. Go to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). +2. Navigate to "Configuration" > "Cloud Providers". + + ![Cloud Providers Page](/images/prowler-app/cloud-providers-page.png) + +3. Click "Add Cloud Provider". + + ![Add a Cloud Provider](/images/prowler-app/add-cloud-provider.png) + +4. Select "Vercel". + + ![Select Vercel](/images/providers/select-vercel-prowler-cloud.png) + +5. Enter the **Team ID** and an optional alias, then click "Next". + + ![Add Vercel Team ID](/images/providers/vercel-team-id-form.png) + + +The Team ID can be found in the Vercel Dashboard under "Settings" > "General". It follows the format `team_xxxxxxxxxxxxxxxxxxxx`. For detailed instructions, see the [Authentication guide](/user-guide/providers/vercel/authentication). + + +### Step 2: Provide Credentials + +1. Enter the **API Token** created in the Vercel Dashboard. + + ![API Token Form](/images/providers/vercel-token-form.png) + +For the complete token creation workflow, follow the [Authentication guide](/user-guide/providers/vercel/authentication#api-token). + +### Step 3: Launch the Scan + +1. Review the connection summary. +2. Choose the scan schedule: run a single scan or set up daily scans (every 24 hours). +3. Click **Launch Scan** to start auditing Vercel. + + ![Launch Scan](/images/providers/vercel-launch-scan.png) + +--- + ## Prowler CLI - + ### Step 1: Set Up Authentication From cccb3a4b945b71eac5e94c1853c033f6f6bcfe16 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:42:49 +0100 Subject: [PATCH 31/36] chore(sdk,mcp): pin direct dependencies to exact versions (#10593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Adriรกn Jesรบs Peรฑa Rodrรญguez --- docs/developer-guide/introduction.mdx | 2 ++ mcp_server/CHANGELOG.md | 4 ++++ mcp_server/pyproject.toml | 2 +- mcp_server/uv.lock | 2 +- poetry.lock | 10 +++++----- prowler/CHANGELOG.md | 1 + pyproject.toml | 8 ++++---- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/developer-guide/introduction.mdx b/docs/developer-guide/introduction.mdx index 2a4aa3abe1..947c4b4c71 100644 --- a/docs/developer-guide/introduction.mdx +++ b/docs/developer-guide/introduction.mdx @@ -163,6 +163,8 @@ These resources help ensure that AI-assisted contributions maintain consistency All dependencies are listed in the `pyproject.toml` file. +The SDK keeps direct dependencies pinned to exact versions, while `poetry.lock` records the full resolved dependency tree and the artifact hashes for every package. Use `poetry install` from the lock file instead of ad-hoc `pip` installs when you need a reproducible environment. + For proper code documentation, refer to the following and follow the code documentation practices presented there: [Google Python Style Guide - Comments and Docstrings](https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings). diff --git a/mcp_server/CHANGELOG.md b/mcp_server/CHANGELOG.md index 21aa71dbf2..e94487e257 100644 --- a/mcp_server/CHANGELOG.md +++ b/mcp_server/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to the **Prowler MCP Server** are documented in this file. - Resource events tool to get timeline for a resource (who, what, when) [(#10412)](https://github.com/prowler-cloud/prowler/pull/10412) +### ๐Ÿ”„ Changed + +- Pin `httpx` dependency to exact version for reproducible installs [(#10593)](https://github.com/prowler-cloud/prowler/pull/10593) + ### ๐Ÿ” Security - `authlib` bumped from 1.6.5 to 1.6.9 to fix CVE-2026-28802 (JWT `alg: none` validation bypass) [(#10579)](https://github.com/prowler-cloud/prowler/pull/10579) diff --git a/mcp_server/pyproject.toml b/mcp_server/pyproject.toml index 4ea4a9859e..2a6885fedb 100644 --- a/mcp_server/pyproject.toml +++ b/mcp_server/pyproject.toml @@ -5,7 +5,7 @@ requires = ["setuptools>=61.0", "wheel"] [project] dependencies = [ "fastmcp==2.14.0", - "httpx>=0.28.0" + "httpx==0.28.1" ] description = "MCP server for Prowler ecosystem" name = "prowler-mcp" diff --git a/mcp_server/uv.lock b/mcp_server/uv.lock index ca1d9482be..bcff18e2d9 100644 --- a/mcp_server/uv.lock +++ b/mcp_server/uv.lock @@ -727,7 +727,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "fastmcp", specifier = "==2.14.0" }, - { name = "httpx", specifier = ">=0.28.0" }, + { name = "httpx", specifier = "==0.28.1" }, ] [[package]] diff --git a/poetry.lock b/poetry.lock index a76112ff76..c0ffadab6f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -808,7 +808,7 @@ description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, @@ -2379,7 +2379,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main", "dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -3938,7 +3938,7 @@ description = "Python package for creating and manipulating graphs and networks" optional = false python-versions = ">=3.10" groups = ["dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, @@ -6094,7 +6094,7 @@ description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["dev"] -markers = "python_version == \"3.10\"" +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -6743,4 +6743,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.13" -content-hash = "91739ee5e383337160f9f08b76944ab4e8629c94084c8a9d115246862557f7c5" +content-hash = "4050d3a95f5bc5448576ca0361fd899b35aa04de28d379cdfd3c2b0db67848ad" diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 8f60b4a7d7..4835fe7f75 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -27,6 +27,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Added `internet-exposed` category to 13 AWS checks (CloudFront, CodeArtifact, EC2, EFS, RDS, SageMaker, Shield, VPC) [(#10502)](https://github.com/prowler-cloud/prowler/pull/10502) - Minimum Python version from 3.9 to 3.10 and updated classifiers to reflect supported versions (3.10, 3.11, 3.12) [(#10464)](https://github.com/prowler-cloud/prowler/pull/10464) +- Pin direct SDK dependencies to exact versions and rely on `poetry.lock` artifact hashes for reproducible installs [(#10593)](https://github.com/prowler-cloud/prowler/pull/10593) - Sensitive CLI flags now warn when values are passed directly, recommending environment variables instead [(#10532)](https://github.com/prowler-cloud/prowler/pull/10532) ### ๐Ÿž Fixed diff --git a/pyproject.toml b/pyproject.toml index a3b6f7dece..0db8391be7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,11 +49,11 @@ dependencies = [ "cryptography==46.0.6", "dash==3.1.1", "dash-bootstrap-components==2.0.3", - "defusedxml>=0.7.1", + "defusedxml==0.7.1", "detect-secrets==1.5.0", "dulwich==0.23.0", "google-api-python-client==2.163.0", - "google-auth-httplib2>=0.1,<0.3", + "google-auth-httplib2==0.2.0", "jsonschema==4.23.0", "kubernetes==32.0.1", "markdown==3.10.2", @@ -63,9 +63,9 @@ dependencies = [ "openstacksdk==4.2.0", "pandas==2.2.3", "py-ocsf-models==0.8.1", - "pydantic (>=2.0,<3.0)", + "pydantic==2.12.5", "pygithub==2.8.0", - "python-dateutil (>=2.9.0.post0,<3.0.0)", + "python-dateutil==2.9.0.post0", "pytz==2025.1", "schema==0.7.5", "shodan==1.31.0", From b898f257f1b25a482523b733eeb2ae6370d7d242 Mon Sep 17 00:00:00 2001 From: Avula Jeevan Yadav Date: Thu, 9 Apr 2026 19:26:29 +0530 Subject: [PATCH 32/36] feat(stepfunctions): add check for secrets in state machine definition (#10570) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../__init__.py | 0 ...ine_no_secrets_in_definition.metadata.json | 44 +++++ ...s_statemachine_no_secrets_in_definition.py | 45 +++++ .../__init__.py | 0 ...temachine_no_secrets_in_definition_test.py | 180 ++++++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py create mode 100644 prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.metadata.json create mode 100644 prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.py create mode 100644 tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py create mode 100644 tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 4835fe7f75..eb7944ff09 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - `entra_conditional_access_policy_device_registration_mfa_required` check and `entra_intune_enrollment_sign_in_frequency_every_time` enhancement for M365 provider [(#10222)](https://github.com/prowler-cloud/prowler/pull/10222) - `entra_conditional_access_policy_block_elevated_insider_risk` check for M365 provider [(#10234)](https://github.com/prowler-cloud/prowler/pull/10234) - `Vercel` provider support with 30 checks [(#10189)](https://github.com/prowler-cloud/prowler/pull/10189) +- `stepfunctions_statemachine_no_secrets_in_definition` check for hardcoded secrets in AWS Step Functions state machine definitions [(#10570)](https://github.com/prowler-cloud/prowler/pull/10570) - CCC improvements with the latest checks and new mappings [(#10625)](https://github.com/prowler-cloud/prowler/pull/10625) ### ๐Ÿ”„ Changed diff --git a/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.metadata.json b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.metadata.json new file mode 100644 index 0000000000..746b53d8fd --- /dev/null +++ b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.metadata.json @@ -0,0 +1,44 @@ +{ + "Provider": "aws", + "CheckID": "stepfunctions_statemachine_no_secrets_in_definition", + "CheckTitle": "Step Functions state machine has no sensitive credentials in its definition", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices", + "TTPs/Credential Access", + "Effects/Data Exposure", + "Sensitive Data Identifications/Security" + ], + "ServiceName": "stepfunctions", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "critical", + "ResourceType": "AwsStepFunctionStateMachine", + "ResourceGroup": "serverless", + "Description": "**AWS Step Functions state machines** are inspected for **hardcoded secrets** (keys, tokens, passwords) embedded directly in the state machine **definition** (Amazon States Language JSON).\n\nSuch values indicate sensitive data is stored directly in task parameters instead of being sourced securely.", + "Risk": "Plaintext secrets in state machine definitions reduce confidentiality: values can be viewed in the AWS Console, CLI, and may leak into execution logs or public outputs. Compromised credentials enable unauthorized AWS actions, lateral movement, and data exfiltration.", + "RelatedUrl": "", + "AdditionalURLs": [ + "https://docs.aws.amazon.com/step-functions/latest/dg/concepts-amazon-states-language.html", + "https://docs.aws.amazon.com/step-functions/latest/dg/security-best-practices.html", + "https://docs.aws.amazon.com/secretsmanager/latest/userguide/integrating_how-services-use-secrets_step-functions.html", + "https://docs.aws.amazon.com/systems-manager/latest/userguide/integration-ps-secretsmanager.html" + ], + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "```yaml\nResources:\n :\n Type: AWS::StepFunctions::StateMachine\n Properties:\n StateMachineName: \n RoleArn: \n DefinitionString: |\n {\n \"Comment\": \"Example state machine\",\n \"StartAt\": \"MyTask\",\n \"States\": {\n \"MyTask\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::aws-sdk:secretsmanager:getSecretValue\",\n \"Parameters\": {\n \"SecretId\": \"\"\n },\n \"End\": true\n }\n }\n }\n```", + "Other": "1. In AWS Console, go to Step Functions and open your state machine\n2. Click Edit\n3. Remove any hardcoded secrets from the definition\n4. Use AWS Secrets Manager or Parameter Store to retrieve secrets at runtime\n5. Grant the state machine IAM role permission to access the secret\n6. Save the updated definition", + "Terraform": "```hcl\nresource \"aws_sfn_state_machine\" \"\" {\n name = \"\"\n role_arn = \"\"\n\n definition = jsonencode({\n Comment = \"Example state machine\"\n StartAt = \"MyTask\"\n States = {\n MyTask = {\n Type = \"Task\"\n Resource = \"arn:aws:states:::aws-sdk:secretsmanager:getSecretValue\"\n Parameters = {\n SecretId = \"\" # Reference secret by name, never hardcode value\n }\n End = true\n }\n }\n })\n}\n```" + }, + "Recommendation": { + "Text": "Store secrets outside the state machine definition and retrieve them securely at runtime using **AWS Secrets Manager** or **AWS Systems Manager Parameter Store**.\n- Use the `aws-sdk:secretsmanager:getSecretValue` integration to fetch secrets dynamically\n- Enforce **least privilege** on the state machine IAM role\n- Rotate secrets regularly and never embed them in the definition", + "Url": "https://hub.prowler.com/check/stepfunctions_statemachine_no_secrets_in_definition" + } + }, + "Categories": [ + "secrets" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.py b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.py new file mode 100644 index 0000000000..db04710029 --- /dev/null +++ b/prowler/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition.py @@ -0,0 +1,45 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.lib.utils.utils import detect_secrets_scan +from prowler.providers.aws.services.stepfunctions.stepfunctions_client import ( + stepfunctions_client, +) + + +class stepfunctions_statemachine_no_secrets_in_definition(Check): + """Check that AWS Step Functions state machine definitions contain no hardcoded secrets.""" + + def execute(self) -> list[Check_Report_AWS]: + findings = [] + secrets_ignore_patterns = stepfunctions_client.audit_config.get( + "secrets_ignore_patterns", [] + ) + for state_machine in stepfunctions_client.state_machines.values(): + report = Check_Report_AWS(metadata=self.metadata(), resource=state_machine) + report.status = "PASS" + report.status_extended = f"No secrets found in Step Functions state machine {state_machine.name} definition." + + if state_machine.definition: + detect_secrets_output = detect_secrets_scan( + data=state_machine.definition, + excluded_secrets=secrets_ignore_patterns, + detect_secrets_plugins=stepfunctions_client.audit_config.get( + "detect_secrets_plugins", + ), + ) + + if detect_secrets_output: + secrets_string = ", ".join( + [ + f"{secret['type']} on line {secret['line_number']}" + for secret in detect_secrets_output + ] + ) + report.status = "FAIL" + report.status_extended = ( + f"Potential {'secrets' if len(detect_secrets_output) > 1 else 'secret'} " + f"found in Step Functions state machine {state_machine.name} definition " + f"-> {secrets_string}." + ) + + findings.append(report) + return findings diff --git a/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py b/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition_test.py b/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition_test.py new file mode 100644 index 0000000000..628525e542 --- /dev/null +++ b/tests/providers/aws/services/stepfunctions/stepfunctions_statemachine_no_secrets_in_definition/stepfunctions_statemachine_no_secrets_in_definition_test.py @@ -0,0 +1,180 @@ +from datetime import datetime +from unittest import mock + +from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_US_EAST_1 + + +class Test_stepfunctions_statemachine_no_secrets_in_definition: + def test_no_statemachines(self): + stepfunctions_client = mock.MagicMock() + stepfunctions_client.state_machines = {} + stepfunctions_client.audit_config = {"secrets_ignore_patterns": []} + + with ( + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_service.StepFunctions", + stepfunctions_client, + ), + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_client", + stepfunctions_client, + ), + ): + from prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition import ( + stepfunctions_statemachine_no_secrets_in_definition, + ) + + check = stepfunctions_statemachine_no_secrets_in_definition() + result = check.execute() + + assert len(result) == 0 + + def test_statemachine_with_no_definition(self): + stepfunctions_client = mock.MagicMock() + + from prowler.providers.aws.services.stepfunctions.stepfunctions_service import ( + StateMachine, + StateMachineStatus, + StateMachineType, + ) + + statemachine_arn = f"arn:aws:states:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:stateMachine:TestStateMachine" + stepfunctions_client.state_machines = { + statemachine_arn: StateMachine( + id="TestStateMachine", + arn=statemachine_arn, + name="TestStateMachine", + status=StateMachineStatus.ACTIVE, + definition=None, + region=AWS_REGION_US_EAST_1, + type=StateMachineType.STANDARD, + creation_date=datetime.now(), + ) + } + stepfunctions_client.audit_config = {"secrets_ignore_patterns": []} + + with ( + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_service.StepFunctions", + stepfunctions_client, + ), + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_client", + stepfunctions_client, + ), + ): + from prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition import ( + stepfunctions_statemachine_no_secrets_in_definition, + ) + + check = stepfunctions_statemachine_no_secrets_in_definition() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "No secrets found in Step Functions state machine TestStateMachine definition." + ) + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == "TestStateMachine" + assert result[0].resource_arn == statemachine_arn + + def test_statemachine_with_no_secrets_in_definition(self): + stepfunctions_client = mock.MagicMock() + + from prowler.providers.aws.services.stepfunctions.stepfunctions_service import ( + StateMachine, + StateMachineStatus, + StateMachineType, + ) + + statemachine_arn = f"arn:aws:states:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:stateMachine:TestStateMachine" + stepfunctions_client.state_machines = { + statemachine_arn: StateMachine( + id="TestStateMachine", + arn=statemachine_arn, + name="TestStateMachine", + status=StateMachineStatus.ACTIVE, + definition='{"Comment": "A simple example", "StartAt": "HelloWorld", "States": {"HelloWorld": {"Type": "Pass", "End": true}}}', + region=AWS_REGION_US_EAST_1, + type=StateMachineType.STANDARD, + creation_date=datetime.now(), + ) + } + stepfunctions_client.audit_config = {"secrets_ignore_patterns": []} + + with ( + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_service.StepFunctions", + stepfunctions_client, + ), + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_client", + stepfunctions_client, + ), + ): + from prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition import ( + stepfunctions_statemachine_no_secrets_in_definition, + ) + + check = stepfunctions_statemachine_no_secrets_in_definition() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "No secrets found in Step Functions state machine TestStateMachine definition." + ) + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == "TestStateMachine" + assert result[0].resource_arn == statemachine_arn + + def test_statemachine_with_secrets_in_definition(self): + stepfunctions_client = mock.MagicMock() + + from prowler.providers.aws.services.stepfunctions.stepfunctions_service import ( + StateMachine, + StateMachineStatus, + StateMachineType, + ) + + statemachine_arn = f"arn:aws:states:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:stateMachine:TestStateMachine" + stepfunctions_client.state_machines = { + statemachine_arn: StateMachine( + id="TestStateMachine", + arn=statemachine_arn, + name="TestStateMachine", + status=StateMachineStatus.ACTIVE, + definition='{"Comment": "Example with secret", "StartAt": "MyTask", "States": {"MyTask": {"Type": "Task", "Parameters": {"api_key": "AKIAIOSFODNN7EXAMPLE"}, "End": true}}}', + region=AWS_REGION_US_EAST_1, + type=StateMachineType.STANDARD, + creation_date=datetime.now(), + ) + } + stepfunctions_client.audit_config = {"secrets_ignore_patterns": []} + + with ( + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_service.StepFunctions", + stepfunctions_client, + ), + mock.patch( + "prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_client", + stepfunctions_client, + ), + ): + from prowler.providers.aws.services.stepfunctions.stepfunctions_statemachine_no_secrets_in_definition.stepfunctions_statemachine_no_secrets_in_definition import ( + stepfunctions_statemachine_no_secrets_in_definition, + ) + + check = stepfunctions_statemachine_no_secrets_in_definition() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert "TestStateMachine" in result[0].status_extended + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == "TestStateMachine" + assert result[0].resource_arn == statemachine_arn From 18cfb191f5c5d5b9edfd7305643a7cd7a0c71dd1 Mon Sep 17 00:00:00 2001 From: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:58:35 +0200 Subject: [PATCH 33/36] docs: rename Prowler App to Prowler Cloud in provider headers (#10634) --- .../providers/alibabacloud/getting-started-alibabacloud.mdx | 2 +- docs/user-guide/providers/aws/getting-started-aws.mdx | 4 ++-- docs/user-guide/providers/azure/getting-started-azure.mdx | 6 +++--- docs/user-guide/providers/gcp/getting-started-gcp.mdx | 4 ++-- docs/user-guide/providers/iac/getting-started-iac.mdx | 2 +- .../user-guide/providers/kubernetes/getting-started-k8s.mdx | 2 +- docs/user-guide/providers/oci/getting-started-oci.mdx | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx b/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx index 0a1d54b079..de8708d867 100644 --- a/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx +++ b/docs/user-guide/providers/alibabacloud/getting-started-alibabacloud.mdx @@ -37,7 +37,7 @@ Before you begin, make sure you have: ![Get Account ID](/images/providers/alibaba-account-id.png) -### Step 2: Access Prowler Cloud or Prowler App +### Step 2: Access Prowler Cloud 1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 2. Go to "Configuration" > "Cloud Providers" diff --git a/docs/user-guide/providers/aws/getting-started-aws.mdx b/docs/user-guide/providers/aws/getting-started-aws.mdx index 7d003d9821..2c94700b15 100644 --- a/docs/user-guide/providers/aws/getting-started-aws.mdx +++ b/docs/user-guide/providers/aws/getting-started-aws.mdx @@ -2,7 +2,7 @@ title: 'Getting Started With AWS on Prowler' --- -## Prowler App +## Prowler Cloud @@ -16,7 +16,7 @@ title: 'Getting Started With AWS on Prowler' ![Account ID detail](/images/providers/aws-account-id.png) -### Step 2: Access Prowler Cloud or Prowler App +### Step 2: Access Prowler Cloud 1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 2. Go to "Configuration" > "Cloud Providers" diff --git a/docs/user-guide/providers/azure/getting-started-azure.mdx b/docs/user-guide/providers/azure/getting-started-azure.mdx index a5299c614b..456c226aab 100644 --- a/docs/user-guide/providers/azure/getting-started-azure.mdx +++ b/docs/user-guide/providers/azure/getting-started-azure.mdx @@ -2,7 +2,7 @@ title: 'Getting Started With Azure on Prowler' --- -## Prowler App +## Prowler Cloud > Walkthrough video onboarding an Azure Subscription using Service Principal. @@ -32,7 +32,7 @@ For detailed instructions on how to create the Service Principal and configure p --- -### Step 2: Access Prowler App +### Step 2: Access Prowler Cloud 1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 2. Navigate to `Configuration` > `Cloud Providers` @@ -51,7 +51,7 @@ For detailed instructions on how to create the Service Principal and configure p ![Add Subscription ID](/images/providers/add-subscription-id.png) -### Step 3: Add Credentials to Prowler App +### Step 3: Add Credentials to Prowler Cloud For Azure, Prowler App uses a service principal application to authenticate. For more information about the process of creating and adding permissions to a service principal refer to this [section](/user-guide/providers/azure/authentication). When you finish creating and adding the [Entra](/user-guide/providers/azure/create-prowler-service-principal#assigning-proper-permissions) and [Subscription](/user-guide/providers/azure/subscriptions) scope permissions to the service principal, enter the `Tenant ID`, `Client ID` and `Client Secret` of the service principal application. diff --git a/docs/user-guide/providers/gcp/getting-started-gcp.mdx b/docs/user-guide/providers/gcp/getting-started-gcp.mdx index 1cdc587d45..c70250c8a9 100644 --- a/docs/user-guide/providers/gcp/getting-started-gcp.mdx +++ b/docs/user-guide/providers/gcp/getting-started-gcp.mdx @@ -2,7 +2,7 @@ title: 'Getting Started With GCP on Prowler' --- -## Prowler App +## Prowler Cloud ### Step 1: Get the GCP Project ID @@ -11,7 +11,7 @@ title: 'Getting Started With GCP on Prowler' ![Get the Project ID](/images/providers/project-id-console.png) -### Step 2: Access Prowler Cloud or Prowler App +### Step 2: Access Prowler Cloud 1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app) 2. Go to "Configuration" > "Cloud Providers" diff --git a/docs/user-guide/providers/iac/getting-started-iac.mdx b/docs/user-guide/providers/iac/getting-started-iac.mdx index 849571b2c8..2aba3cf551 100644 --- a/docs/user-guide/providers/iac/getting-started-iac.mdx +++ b/docs/user-guide/providers/iac/getting-started-iac.mdx @@ -31,7 +31,7 @@ Prowler IaC provider scans the following Infrastructure as Code configurations f - Mutelist logic ([filtering](https://trivy.dev/latest/docs/configuration/filtering/)) is handled by Trivy, not Prowler. - Results are output in the same formats as other Prowler providers (CSV, JSON, HTML, etc.). -## Prowler App +## Prowler Cloud diff --git a/docs/user-guide/providers/kubernetes/getting-started-k8s.mdx b/docs/user-guide/providers/kubernetes/getting-started-k8s.mdx index c4f4822792..aff63b81a3 100644 --- a/docs/user-guide/providers/kubernetes/getting-started-k8s.mdx +++ b/docs/user-guide/providers/kubernetes/getting-started-k8s.mdx @@ -2,7 +2,7 @@ title: 'Getting Started with Kubernetes' --- -## Prowler App +## Prowler Cloud ### Step 1: Access Prowler Cloud/App diff --git a/docs/user-guide/providers/oci/getting-started-oci.mdx b/docs/user-guide/providers/oci/getting-started-oci.mdx index 8affa2f992..459d9ad685 100644 --- a/docs/user-guide/providers/oci/getting-started-oci.mdx +++ b/docs/user-guide/providers/oci/getting-started-oci.mdx @@ -14,7 +14,7 @@ The following steps apply to Prowler Cloud and the self-hosted Prowler App. 3. Generate or locate the API key fingerprint and private key for that user. Follow the [Config File Authentication steps](/user-guide/providers/oci/authentication#config-file-authentication-manual-api-key-setup) to create or rotate the key pair and copy the fingerprint. 4. Note the **Region** identifier to scan (for example, `us-ashburn-1`). -### Step 2: Access Prowler Cloud or Prowler App +### Step 2: Access Prowler Cloud 1. Navigate to [Prowler Cloud](https://cloud.prowler.com/) or launch [Prowler App](/user-guide/tutorials/prowler-app). 2. Go to **Configuration** โ†’ **Cloud Providers** and click **Add Cloud Provider**. ![Add OCI Cloud Provider](./images/oci-add-cloud-provider.png) From 4e508b69c955d3fde316cc836cda8bd903d17c9a Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:23:50 +0200 Subject: [PATCH 34/36] fix(vercel): use canonical Hub URLs in check metadata (#10636) --- ...thentication_no_stale_tokens.metadata.json | 2 +- ...entication_token_not_expired.metadata.json | 2 +- ...roduction_uses_stable_target.metadata.json | 2 +- ...main_dns_properly_configured.metadata.json | 2 +- ...domain_ssl_certificate_valid.metadata.json | 2 +- .../domain_verified.metadata.json | 2 +- ...o_expose_system_env_disabled.metadata.json | 2 +- ...eployment_protection_enabled.metadata.json | 2 +- ...t_directory_listing_disabled.metadata.json | 2 +- ...nment_no_overly_broad_target.metadata.json | 2 +- ...ent_no_secrets_in_plain_type.metadata.json | 2 +- ...oduction_vars_not_in_preview.metadata.json | 2 +- ..._git_fork_protection_enabled.metadata.json | 2 +- ..._password_protection_enabled.metadata.json | 2 +- ...eployment_protection_enabled.metadata.json | 2 +- ...ject_skew_protection_enabled.metadata.json | 2 +- ...rity_custom_rules_configured.metadata.json | 2 +- ...ip_blocking_rules_configured.metadata.json | 2 +- ...ity_managed_rulesets_enabled.metadata.json | 2 +- ...ity_rate_limiting_configured.metadata.json | 2 +- .../security_waf_enabled.metadata.json | 2 +- .../team_directory_sync_enabled.metadata.json | 2 +- ..._member_role_least_privilege.metadata.json | 2 +- .../team_no_stale_invitations.metadata.json | 2 +- .../team_saml_sso_enabled.metadata.json | 2 +- .../team_saml_sso_enforced.metadata.json | 2 +- tests/lib/check/check_test.py | 28 +++++++++++++++++++ 27 files changed, 54 insertions(+), 26 deletions(-) diff --git a/prowler/providers/vercel/services/authentication/authentication_no_stale_tokens/authentication_no_stale_tokens.metadata.json b/prowler/providers/vercel/services/authentication/authentication_no_stale_tokens/authentication_no_stale_tokens.metadata.json index d94e12f0b9..f4863ada5f 100644 --- a/prowler/providers/vercel/services/authentication/authentication_no_stale_tokens/authentication_no_stale_tokens.metadata.json +++ b/prowler/providers/vercel/services/authentication/authentication_no_stale_tokens/authentication_no_stale_tokens.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Regularly audit API tokens and revoke any that have not been used within 90 days. Implement a token lifecycle management process that includes periodic reviews, automatic expiration dates, and documentation of each token's purpose and owner.", - "Url": "https://hub.prowler.com/checks/vercel/authentication_no_stale_tokens" + "Url": "https://hub.prowler.com/check/authentication_no_stale_tokens" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/authentication/authentication_token_not_expired/authentication_token_not_expired.metadata.json b/prowler/providers/vercel/services/authentication/authentication_token_not_expired/authentication_token_not_expired.metadata.json index dca48e73bf..47e5087cf5 100644 --- a/prowler/providers/vercel/services/authentication/authentication_token_not_expired/authentication_token_not_expired.metadata.json +++ b/prowler/providers/vercel/services/authentication/authentication_token_not_expired/authentication_token_not_expired.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Remove expired tokens and create new ones with appropriate expiration dates. Implement a token rotation schedule to ensure tokens are refreshed before they expire. Update all integrations and automation that depend on the replaced tokens.", - "Url": "https://hub.prowler.com/checks/vercel/authentication_token_not_expired" + "Url": "https://hub.prowler.com/check/authentication_token_not_expired" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/deployment/deployment_production_uses_stable_target/deployment_production_uses_stable_target.metadata.json b/prowler/providers/vercel/services/deployment/deployment_production_uses_stable_target/deployment_production_uses_stable_target.metadata.json index 8a7cc70d40..25416e6882 100644 --- a/prowler/providers/vercel/services/deployment/deployment_production_uses_stable_target/deployment_production_uses_stable_target.metadata.json +++ b/prowler/providers/vercel/services/deployment/deployment_production_uses_stable_target/deployment_production_uses_stable_target.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Configure the production branch to main or master and ensure all production deployments go through the standard merge workflow. Use branch protection rules in your Git provider to prevent direct pushes to the production branch.", - "Url": "https://hub.prowler.com/checks/vercel/deployment_production_uses_stable_target" + "Url": "https://hub.prowler.com/check/deployment_production_uses_stable_target" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/domain/domain_dns_properly_configured/domain_dns_properly_configured.metadata.json b/prowler/providers/vercel/services/domain/domain_dns_properly_configured/domain_dns_properly_configured.metadata.json index f9104ee960..e2450da8f1 100644 --- a/prowler/providers/vercel/services/domain/domain_dns_properly_configured/domain_dns_properly_configured.metadata.json +++ b/prowler/providers/vercel/services/domain/domain_dns_properly_configured/domain_dns_properly_configured.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Update DNS records at your domain registrar to correctly point to Vercel. Use a CNAME record for subdomains or an A record for apex domains. Verify the configuration in the Vercel dashboard after making changes.", - "Url": "https://hub.prowler.com/checks/vercel/domain_dns_properly_configured" + "Url": "https://hub.prowler.com/check/domain_dns_properly_configured" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid.metadata.json b/prowler/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid.metadata.json index f15892df61..ac683cd71f 100644 --- a/prowler/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid.metadata.json +++ b/prowler/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Ensure domain DNS records are properly configured to point to Vercel. Once DNS is validated, Vercel automatically provisions and renews SSL/TLS certificates. Check the domain configuration in the Vercel dashboard if the certificate is not being issued.", - "Url": "https://hub.prowler.com/checks/vercel/domain_ssl_certificate_valid" + "Url": "https://hub.prowler.com/check/domain_ssl_certificate_valid" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/domain/domain_verified/domain_verified.metadata.json b/prowler/providers/vercel/services/domain/domain_verified/domain_verified.metadata.json index f520fb00d8..1e79a433ba 100644 --- a/prowler/providers/vercel/services/domain/domain_verified/domain_verified.metadata.json +++ b/prowler/providers/vercel/services/domain/domain_verified/domain_verified.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Complete domain verification by configuring the required DNS records at your domain registrar. Remove any domains that are no longer needed to reduce the attack surface. Regularly audit domain configurations to ensure all domains remain verified.", - "Url": "https://hub.prowler.com/checks/vercel/domain_verified" + "Url": "https://hub.prowler.com/check/domain_verified" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_auto_expose_system_env_disabled/project_auto_expose_system_env_disabled.metadata.json b/prowler/providers/vercel/services/project/project_auto_expose_system_env_disabled/project_auto_expose_system_env_disabled.metadata.json index bf7adc2832..21c3f118e1 100644 --- a/prowler/providers/vercel/services/project/project_auto_expose_system_env_disabled/project_auto_expose_system_env_disabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_auto_expose_system_env_disabled/project_auto_expose_system_env_disabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Disable automatic exposure of system environment variables and explicitly define only the variables required by your application. This follows the principle of least privilege and reduces the risk of leaking internal infrastructure details through client-side code.", - "Url": "https://hub.prowler.com/checks/vercel/project_auto_expose_system_env_disabled" + "Url": "https://hub.prowler.com/check/project_auto_expose_system_env_disabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_deployment_protection_enabled/project_deployment_protection_enabled.metadata.json b/prowler/providers/vercel/services/project/project_deployment_protection_enabled/project_deployment_protection_enabled.metadata.json index c704b42784..521610c617 100644 --- a/prowler/providers/vercel/services/project/project_deployment_protection_enabled/project_deployment_protection_enabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_deployment_protection_enabled/project_deployment_protection_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable deployment protection on preview deployments to require authentication before visitors can access preview URLs. Use 'Standard Protection' for Vercel Authentication or configure trusted IP ranges for more granular control.", - "Url": "https://hub.prowler.com/checks/vercel/project_deployment_protection_enabled" + "Url": "https://hub.prowler.com/check/project_deployment_protection_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_directory_listing_disabled/project_directory_listing_disabled.metadata.json b/prowler/providers/vercel/services/project/project_directory_listing_disabled/project_directory_listing_disabled.metadata.json index b9de49aa0e..b477a5984f 100644 --- a/prowler/providers/vercel/services/project/project_directory_listing_disabled/project_directory_listing_disabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_directory_listing_disabled/project_directory_listing_disabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Disable directory listing to prevent visitors from browsing the file structure of your deployments. Ensure that all directories either contain an index file or return a 404 response when accessed directly.", - "Url": "https://hub.prowler.com/checks/vercel/project_directory_listing_disabled" + "Url": "https://hub.prowler.com/check/project_directory_listing_disabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_environment_no_overly_broad_target/project_environment_no_overly_broad_target.metadata.json b/prowler/providers/vercel/services/project/project_environment_no_overly_broad_target/project_environment_no_overly_broad_target.metadata.json index 2467c1b104..c9a418a503 100644 --- a/prowler/providers/vercel/services/project/project_environment_no_overly_broad_target/project_environment_no_overly_broad_target.metadata.json +++ b/prowler/providers/vercel/services/project/project_environment_no_overly_broad_target/project_environment_no_overly_broad_target.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Follow the **principle of least privilege** for environment variable targeting.\n- Assign each variable to only the environments where it is actually needed\n- Use different credentials for production, preview, and development environments\n- Non-sensitive configuration (e.g. feature flags, public URLs) may be acceptable in multiple environments but should still be reviewed\n- Regularly audit environment variable targets to prevent scope creep", - "Url": "https://hub.prowler.com/checks/vercel/project_environment_no_overly_broad_target" + "Url": "https://hub.prowler.com/check/project_environment_no_overly_broad_target" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_environment_no_secrets_in_plain_type/project_environment_no_secrets_in_plain_type.metadata.json b/prowler/providers/vercel/services/project/project_environment_no_secrets_in_plain_type/project_environment_no_secrets_in_plain_type.metadata.json index f8d5621914..90fea53eea 100644 --- a/prowler/providers/vercel/services/project/project_environment_no_secrets_in_plain_type/project_environment_no_secrets_in_plain_type.metadata.json +++ b/prowler/providers/vercel/services/project/project_environment_no_secrets_in_plain_type/project_environment_no_secrets_in_plain_type.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Use the **Sensitive** type for all environment variables that contain secrets, keys, tokens, or passwords.\n- Sensitive variables are never exposed in the dashboard or API responses after creation\n- Rotate all credentials that were previously stored as plain text\n- Implement naming conventions that make it easy to identify secret variables", - "Url": "https://hub.prowler.com/checks/vercel/project_environment_no_secrets_in_plain_type" + "Url": "https://hub.prowler.com/check/project_environment_no_secrets_in_plain_type" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_environment_production_vars_not_in_preview/project_environment_production_vars_not_in_preview.metadata.json b/prowler/providers/vercel/services/project/project_environment_production_vars_not_in_preview/project_environment_production_vars_not_in_preview.metadata.json index 55f468fa8a..6fc3e3af79 100644 --- a/prowler/providers/vercel/services/project/project_environment_production_vars_not_in_preview/project_environment_production_vars_not_in_preview.metadata.json +++ b/prowler/providers/vercel/services/project/project_environment_production_vars_not_in_preview/project_environment_production_vars_not_in_preview.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Maintain strict **environment separation** between production and preview deployments.\n- Use dedicated, limited-scope credentials for preview environments\n- Never share production database credentials, API keys, or signing keys with preview builds\n- Enable Vercel's deployment protection features to further restrict access to preview deployments\n- Regularly audit which environment variables target multiple environments", - "Url": "https://hub.prowler.com/checks/vercel/project_environment_production_vars_not_in_preview" + "Url": "https://hub.prowler.com/check/project_environment_production_vars_not_in_preview" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_git_fork_protection_enabled/project_git_fork_protection_enabled.metadata.json b/prowler/providers/vercel/services/project/project_git_fork_protection_enabled/project_git_fork_protection_enabled.metadata.json index 744a227d61..8e3db04fcd 100644 --- a/prowler/providers/vercel/services/project/project_git_fork_protection_enabled/project_git_fork_protection_enabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_git_fork_protection_enabled/project_git_fork_protection_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable Git fork protection to require explicit authorization before pull requests from forked repositories can trigger deployments. This prevents untrusted contributors from accessing environment variables and secrets through the build process. For open-source projects, review fork PRs manually before allowing builds.", - "Url": "https://hub.prowler.com/checks/vercel/project_git_fork_protection_enabled" + "Url": "https://hub.prowler.com/check/project_git_fork_protection_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_password_protection_enabled/project_password_protection_enabled.metadata.json b/prowler/providers/vercel/services/project/project_password_protection_enabled/project_password_protection_enabled.metadata.json index 58e3e46e41..2db77410d9 100644 --- a/prowler/providers/vercel/services/project/project_password_protection_enabled/project_password_protection_enabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_password_protection_enabled/project_password_protection_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable password protection to add a shared-password gate to your deployments. This is especially recommended for preview deployments shared with external clients or stakeholders who do not have Vercel accounts. Combine with Vercel Authentication for defense-in-depth.", - "Url": "https://hub.prowler.com/checks/vercel/project_password_protection_enabled" + "Url": "https://hub.prowler.com/check/project_password_protection_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_production_deployment_protection_enabled/project_production_deployment_protection_enabled.metadata.json b/prowler/providers/vercel/services/project/project_production_deployment_protection_enabled/project_production_deployment_protection_enabled.metadata.json index 213bc51d07..3760eefb57 100644 --- a/prowler/providers/vercel/services/project/project_production_deployment_protection_enabled/project_production_deployment_protection_enabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_production_deployment_protection_enabled/project_production_deployment_protection_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable deployment protection on production deployments for applications that should not be publicly accessible. This is critical for internal tools, admin dashboards, and pre-launch applications where unauthorized access could lead to data exposure or system compromise.", - "Url": "https://hub.prowler.com/checks/vercel/project_production_deployment_protection_enabled" + "Url": "https://hub.prowler.com/check/project_production_deployment_protection_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/project/project_skew_protection_enabled/project_skew_protection_enabled.metadata.json b/prowler/providers/vercel/services/project/project_skew_protection_enabled/project_skew_protection_enabled.metadata.json index b73aaa6991..a0a4f70cee 100644 --- a/prowler/providers/vercel/services/project/project_skew_protection_enabled/project_skew_protection_enabled.metadata.json +++ b/prowler/providers/vercel/services/project/project_skew_protection_enabled/project_skew_protection_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable skew protection to ensure that all client requests during a deployment rollout are routed to the same deployment version that served the initial page. This prevents version mismatch errors and ensures a consistent user experience during deployments.", - "Url": "https://hub.prowler.com/checks/vercel/project_skew_protection_enabled" + "Url": "https://hub.prowler.com/check/project_skew_protection_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/security/security_custom_rules_configured/security_custom_rules_configured.metadata.json b/prowler/providers/vercel/services/security/security_custom_rules_configured/security_custom_rules_configured.metadata.json index c3f986b173..a4b53baf4f 100644 --- a/prowler/providers/vercel/services/security/security_custom_rules_configured/security_custom_rules_configured.metadata.json +++ b/prowler/providers/vercel/services/security/security_custom_rules_configured/security_custom_rules_configured.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Configure custom firewall rules to protect application-specific endpoints and enforce security policies. Focus on protecting admin panels, API routes, authentication endpoints, and any paths that handle sensitive data.", - "Url": "https://hub.prowler.com/checks/vercel/security_custom_rules_configured" + "Url": "https://hub.prowler.com/check/security_custom_rules_configured" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/security/security_ip_blocking_rules_configured/security_ip_blocking_rules_configured.metadata.json b/prowler/providers/vercel/services/security/security_ip_blocking_rules_configured/security_ip_blocking_rules_configured.metadata.json index cc7712d4ec..a02cd35324 100644 --- a/prowler/providers/vercel/services/security/security_ip_blocking_rules_configured/security_ip_blocking_rules_configured.metadata.json +++ b/prowler/providers/vercel/services/security/security_ip_blocking_rules_configured/security_ip_blocking_rules_configured.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Configure IP blocking rules to deny traffic from known malicious sources. Maintain a blocklist of IPs identified through security monitoring, threat intelligence feeds, or incident investigation. Regularly review and update the blocklist.", - "Url": "https://hub.prowler.com/checks/vercel/security_ip_blocking_rules_configured" + "Url": "https://hub.prowler.com/check/security_ip_blocking_rules_configured" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/security/security_managed_rulesets_enabled/security_managed_rulesets_enabled.metadata.json b/prowler/providers/vercel/services/security/security_managed_rulesets_enabled/security_managed_rulesets_enabled.metadata.json index 95d7db6d20..ee66a3be21 100644 --- a/prowler/providers/vercel/services/security/security_managed_rulesets_enabled/security_managed_rulesets_enabled.metadata.json +++ b/prowler/providers/vercel/services/security/security_managed_rulesets_enabled/security_managed_rulesets_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable managed WAF rulesets to benefit from Vercel-curated protection against common attack patterns. If you are on a plan that does not support managed rulesets, consider upgrading to the Enterprise plan for enhanced security features.", - "Url": "https://hub.prowler.com/checks/vercel/security_managed_rulesets_enabled" + "Url": "https://hub.prowler.com/check/security_managed_rulesets_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/security/security_rate_limiting_configured/security_rate_limiting_configured.metadata.json b/prowler/providers/vercel/services/security/security_rate_limiting_configured/security_rate_limiting_configured.metadata.json index 28a9c44d5f..8a804233a5 100644 --- a/prowler/providers/vercel/services/security/security_rate_limiting_configured/security_rate_limiting_configured.metadata.json +++ b/prowler/providers/vercel/services/security/security_rate_limiting_configured/security_rate_limiting_configured.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Configure rate limiting rules to protect critical endpoints such as authentication, API routes, and form submissions. Start with conservative thresholds and adjust based on traffic patterns to avoid blocking legitimate users.", - "Url": "https://hub.prowler.com/checks/vercel/security_rate_limiting_configured" + "Url": "https://hub.prowler.com/check/security_rate_limiting_configured" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/security/security_waf_enabled/security_waf_enabled.metadata.json b/prowler/providers/vercel/services/security/security_waf_enabled/security_waf_enabled.metadata.json index c758c82f18..7598e7cccd 100644 --- a/prowler/providers/vercel/services/security/security_waf_enabled/security_waf_enabled.metadata.json +++ b/prowler/providers/vercel/services/security/security_waf_enabled/security_waf_enabled.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Enable the Vercel Web Application Firewall to protect your application against common web attacks. Start with managed rulesets for baseline protection and add custom rules as needed based on your application's threat model.", - "Url": "https://hub.prowler.com/checks/vercel/security_waf_enabled" + "Url": "https://hub.prowler.com/check/security_waf_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/team/team_directory_sync_enabled/team_directory_sync_enabled.metadata.json b/prowler/providers/vercel/services/team/team_directory_sync_enabled/team_directory_sync_enabled.metadata.json index 37019b79da..fda5c7b94d 100644 --- a/prowler/providers/vercel/services/team/team_directory_sync_enabled/team_directory_sync_enabled.metadata.json +++ b/prowler/providers/vercel/services/team/team_directory_sync_enabled/team_directory_sync_enabled.metadata.json @@ -25,7 +25,7 @@ }, "Recommendation": { "Text": "Enable directory sync (SCIM) to automate user lifecycle management. This ensures that team membership stays synchronized with your identity provider, automatically provisioning new members and revoking access when employees leave or change roles.", - "Url": "https://hub.prowler.com/checks/vercel/team_directory_sync_enabled" + "Url": "https://hub.prowler.com/check/team_directory_sync_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege.metadata.json b/prowler/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege.metadata.json index 0e4750d703..37abf769ef 100644 --- a/prowler/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege.metadata.json +++ b/prowler/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Limit the number of team owners to the minimum required for administration. Assign the least privileged role necessary for each member's responsibilities. Use MEMBER, DEVELOPER, or VIEWER roles for non-administrative team members.", - "Url": "https://hub.prowler.com/checks/vercel/team_member_role_least_privilege" + "Url": "https://hub.prowler.com/check/team_member_role_least_privilege" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/team/team_no_stale_invitations/team_no_stale_invitations.metadata.json b/prowler/providers/vercel/services/team/team_no_stale_invitations/team_no_stale_invitations.metadata.json index d05461c5c1..16a1d942e1 100644 --- a/prowler/providers/vercel/services/team/team_no_stale_invitations/team_no_stale_invitations.metadata.json +++ b/prowler/providers/vercel/services/team/team_no_stale_invitations/team_no_stale_invitations.metadata.json @@ -24,7 +24,7 @@ }, "Recommendation": { "Text": "Regularly review and revoke stale team invitations. Establish a process to follow up on pending invitations within a reasonable timeframe and revoke those that are no longer needed to reduce the risk of unauthorized access.", - "Url": "https://hub.prowler.com/checks/vercel/team_no_stale_invitations" + "Url": "https://hub.prowler.com/check/team_no_stale_invitations" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/team/team_saml_sso_enabled/team_saml_sso_enabled.metadata.json b/prowler/providers/vercel/services/team/team_saml_sso_enabled/team_saml_sso_enabled.metadata.json index ebbe85ebc9..21785bf482 100644 --- a/prowler/providers/vercel/services/team/team_saml_sso_enabled/team_saml_sso_enabled.metadata.json +++ b/prowler/providers/vercel/services/team/team_saml_sso_enabled/team_saml_sso_enabled.metadata.json @@ -25,7 +25,7 @@ }, "Recommendation": { "Text": "Enable SAML SSO for the Vercel team to centralize authentication through your organization's identity provider. This ensures consistent security policies, simplifies user lifecycle management, and enables enforcement of MFA and other access controls.", - "Url": "https://hub.prowler.com/checks/vercel/team_saml_sso_enabled" + "Url": "https://hub.prowler.com/check/team_saml_sso_enabled" } }, "Categories": [ diff --git a/prowler/providers/vercel/services/team/team_saml_sso_enforced/team_saml_sso_enforced.metadata.json b/prowler/providers/vercel/services/team/team_saml_sso_enforced/team_saml_sso_enforced.metadata.json index f4de8e7ebe..feb43bc179 100644 --- a/prowler/providers/vercel/services/team/team_saml_sso_enforced/team_saml_sso_enforced.metadata.json +++ b/prowler/providers/vercel/services/team/team_saml_sso_enforced/team_saml_sso_enforced.metadata.json @@ -25,7 +25,7 @@ }, "Recommendation": { "Text": "Enforce SAML SSO for all team members to ensure authentication is managed exclusively through your identity provider. This prevents credential bypass, enforces MFA policies, and provides centralized access control and audit capabilities.", - "Url": "https://hub.prowler.com/checks/vercel/team_saml_sso_enforced" + "Url": "https://hub.prowler.com/check/team_saml_sso_enforced" } }, "Categories": [ diff --git a/tests/lib/check/check_test.py b/tests/lib/check/check_test.py index 84708b96b1..cda33e8fc6 100644 --- a/tests/lib/check/check_test.py +++ b/tests/lib/check/check_test.py @@ -1048,6 +1048,34 @@ class TestCheck: ) self.verify_metadata_check_id(base_directory) + def test_vercel_checks_metadata_is_valid(self): + base_directory = os.path.abspath( + os.path.join( + os.path.dirname(__file__), + "../../../", + "prowler/providers/vercel/services", + ) + ) + self.verify_metadata_check_id(base_directory) + + def test_vercel_checks_metadata_use_canonical_hub_urls(self): + base_directory = pathlib.Path(__file__).resolve().parents[3] / "prowler" + provider_path = base_directory / "providers" / "vercel" / "services" + + invalid_urls = [] + + for metadata_file_path in provider_path.rglob("*.metadata.json"): + with metadata_file_path.open("r") as metadata_file: + data = json.load(metadata_file) + + recommendation = data.get("Remediation", {}).get("Recommendation", {}) + url = recommendation.get("Url", "") + + if url.startswith("https://hub.prowler.com/checks/vercel/"): + invalid_urls.append(f"{metadata_file_path}: {url}") + + assert not invalid_urls, "\n".join(invalid_urls) + def verify_metadata_check_id(self, provider_path): errors = [] # Walk through the base directory to find all service directories From 63174caf985c932f21a08b71f5abccd4e53f9055 Mon Sep 17 00:00:00 2001 From: "Pablo Fernandez Guerra (PFE)" <148432447+pfe-nazaries@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:51:54 +0200 Subject: [PATCH 35/36] docs: add multi-tenant (organizations) management guide (#10638) Co-authored-by: Pablo F.G Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: David --- docs/docs.json | 1 + .../create-organization-button.png | Bin 0 -> 37821 bytes .../create-organization-modal.png | Bin 0 -> 13842 bytes .../delete-active-organization-modal.png | Bin 0 -> 37118 bytes .../delete-organization-modal.png | Bin 0 -> 23433 bytes .../multi-tenant/edit-organization-modal.png | Bin 0 -> 13031 bytes .../multi-tenant/organizations-card.png | Bin 0 -> 102728 bytes .../multi-tenant/sign-in-invitation.png | Bin 0 -> 72756 bytes .../switch-organization-modal.png | Bin 0 -> 14714 bytes .../tutorials/prowler-app-multi-tenant.mdx | 151 ++++++++++++++++++ 10 files changed, 152 insertions(+) create mode 100644 docs/images/prowler-app/multi-tenant/create-organization-button.png create mode 100644 docs/images/prowler-app/multi-tenant/create-organization-modal.png create mode 100644 docs/images/prowler-app/multi-tenant/delete-active-organization-modal.png create mode 100644 docs/images/prowler-app/multi-tenant/delete-organization-modal.png create mode 100644 docs/images/prowler-app/multi-tenant/edit-organization-modal.png create mode 100644 docs/images/prowler-app/multi-tenant/organizations-card.png create mode 100644 docs/images/prowler-app/multi-tenant/sign-in-invitation.png create mode 100644 docs/images/prowler-app/multi-tenant/switch-organization-modal.png create mode 100644 docs/user-guide/tutorials/prowler-app-multi-tenant.mdx diff --git a/docs/docs.json b/docs/docs.json index 2e39c4beac..c76b7174ef 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -98,6 +98,7 @@ ] }, "user-guide/tutorials/prowler-app-rbac", + "user-guide/tutorials/prowler-app-multi-tenant", "user-guide/tutorials/prowler-app-api-keys", "user-guide/tutorials/prowler-app-import-findings", { diff --git a/docs/images/prowler-app/multi-tenant/create-organization-button.png b/docs/images/prowler-app/multi-tenant/create-organization-button.png new file mode 100644 index 0000000000000000000000000000000000000000..70675c334ff3b121597b4f7400e08375d7dda7c9 GIT binary patch literal 37821 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 Rl1&9VfUTDJ(`fvj{ueBa6qEn} literal 0 HcmV?d00001 diff --git a/docs/images/prowler-app/multi-tenant/create-organization-modal.png b/docs/images/prowler-app/multi-tenant/create-organization-modal.png new file mode 100644 index 0000000000000000000000000000000000000000..f0f932035cd121b8790800018cb54ae90853016f GIT binary patch literal 13842 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

)LCMC-yur$d$?Az_4D%^5Pq7g0}&&^ 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 literal 0 HcmV?d00001 diff --git a/docs/images/prowler-app/multi-tenant/delete-organization-modal.png b/docs/images/prowler-app/multi-tenant/delete-organization-modal.png new file mode 100644 index 0000000000000000000000000000000000000000..dd06f937e9e41bcc92dac4b88085598995547a38 GIT binary patch literal 23433 zcmc$_2UL?!*Ekq@uhNm;RC-4UARt{pdI#w>^b#a==}o$TfOL>1HT2#QQL2QRP*iFH zib2}O-}}Db_wAnDb9VRq_v}sXGdJ_h+-L4QlbJhr?!EhZw+*1wQqxoeU||6O8ki5@ z4i3mv1-m%|06IE=M*skT5P*xt1i-^km?8iLEav~B)vz7_aQ?~11_0vS0J#4yql-!Z z0*2c^b^ev&WX1sqFges11i!=nPibtCcR2r{0hgG203|~eO-)Q{=-}t%^ujag(+-0EoTe--;bCx{)L{2eg2t}!U#;Nus7 z=_U~j{X96p=PwjG-wVTT+VF8_lDc?SM{?qB%(E=irdj14g<0|xH{lmSivFMvLP9bg7{1`q>C07Nk#i~ox{ z693du0eAy^03iTBfE&OC;0g%9)K*7AA%Fme76XW2Q0i}AW9nky zzx(jN^SsM2@ADS`fb;sl^X&5h04SzU8DRgN$Ndffpm+rUbj#KX(?;Nc?)NhxWW$FeF< zRn^orG_?$kj7>~2;yE}vIlH*Jx%&qM1_gsdUdFtNjf+o6Ov=p4&dJStlV4C)UQt<9 zT~qtMrM0cS1KQcuJv=fxHa;;qH9fzuxU{_Tbrl9j?CkFCfBXL90Cjf$^Vh|1^yQzw za$x~*{v{UX`Y*};4{}jqdxAy(zmn{~1p9Bf)&MF1?0*0U8yg1?2L}fa z9}ffgg!q4fkeKivApSRy{sZKHf#Sd54#NZs!vhx=mjLsnBq1W9{C^C08<+`%>kbAW z#lgZ1CLAh&BH&uOEa`y+@q@C+|9`RZe6Sy{Wa50wO;+cpsE5AF{;Iilj>m=J`3T9) zmj^b+dRyNgj{$rFOv|>eWft3n@r0AFb!2~tZO-nwUEJd$scTo`ml%?rpmB8Y58Iz^ zQn3kq!glxhU-Bu;++>H7Lb%X*@U6sKG4u#;i$n>)?fHSSJe>wt=WB6|`&d3HDLyf- z0_BZ5?%=#_wjqiHHWHv7%JRYqMc3-HNkp~o!9<_P86{lal9%45B-nIPVf4bU&xeSc zrSyjHf)p8%5Y7$}zbWmdh4b4&J!DtnjvE@-#kg%8=Yd0}kd&G(`PInZ4T_`?`GK3% zaFT1YKJ-|v+eNr2>Ne$;Y5rOf6ioK(tK~b$RdQ_X2AA35b-m^;)!Q7>sjf4&k%3i@ zi%4`cJP(yOa)+5V++kvQ#$9AI{Nk#w5me&k&y1o8Q$#1ZY9yDgMbNaR;PUPC@jC!3 zy6O0Wl>_bAtp$Tce|T4Lwr?gxeejS=IQt980rp-c%27lpcI*P?6@E5AEWO zx_3)?!#X}~S&0%H&$@|vZ=Nk)m<%owVO;qr4iY$!OU*x%E1{j)iHKM17)U%3tQYhW z=0Q&8OZ1d{zp3a`|_D?|J!is4(_fkg>M zPB%n8u$dbrN2RwVqi<%%uQ8D;e+u=us0 z{%FUF$#l^0hm`sxhZmP}Q9Rj@bR>dIZ)afe6c#*G3}|leLfIxjG#%#lMtD?P*y#Dvm=aZN6dvA_?4=q$rrG1#>Uy0kr~XmTrmcX{G|PqBw4 z^f)J1%3FX!a3)bIn^-%R_M))}9zh8SyGiP2M)Pf7v^o|{M74tqBBSXrhl!CG)^B?g!RCe3md>Ke>}b_&{%F-YL>h6>2;yVcKxmF zVay#cW3L#AS8u7`eY^kqh+dJi|55m-2&R6bHM7lYU1aYc$*PKd{?K$O<~OX*i9|0u z&NPzHxJS-pLpw3n>jTZg$NE$&G}plX*Jyw5wWofTQ*CXUGG-lGo1r0I74>qHp9tq@ zF#~mif|M^-(T+@8xo}V)@;G;Gd^wAZ?aDyMVxLR!1GYyZx3j1==Qpaz65eH)^zI+i zRG>D3aA3QkpXEckei5iFnnX4Eqql(NOl5Bq>t><(*DkirZ;fR9cylv?a`4%PJHXL5 z>9lQRZmCcW#E>j)4j5j}|{-79; zOCm?;*jcO+QT;mOY30TTDEHe3e33e#zmwahyaw#O?|=VeBv(_?G+&xZmQ5%9WgCCr7V8Dn|&X# z`(?Q#C2tkU6`gEhB#5oJ0k{Y{VtcJfPt7?XZLczVmCyC;zS2b^mpCnZ%wF6s)gqNm zDU#%Z7oCNgP)5hRpTPa2Iv0)TgvP-%5Y*NlltMdpoU;--SVN2%*)@Cw8A(_7wxPrF zLKA~*IKBQA=$GdRM>2`v6^rpwgr>kxZ(=LKMQ4q&*3<QQOL&amF)&0P@@h?2D*HP8Ot#IL}m$nJN z^au`^g1Y;;`sclV#rH#V$4%Nz4Bc4TJm&>6x}_Y)M`GeYg95U@kMge6!48A7C@vc$ zU8xHk4X3Bp9Tw+){+c3R0PEwIcLY2|0G!9)eJ^s~ESHc*IGskjAarUwpvda6eEcSy z)N!8XT)nnB+>IXRaa_`G3@jd7ZEX19bNC(L*bPN+QGrgZUsD{KRh!W7yj{Be9Oq$e zsMj4&7bG&CDUmiA^r-5ivtpiHmhX$MOZ9Er)!?12(LTPXD-aSmNvf?Lim02;P*nhn z?Z}JkZC42Ww2>cuK%o-%i-NOLW;FBI7Fn-e==L0oo1rUg`R$NP$6LT*C%ysUq>~eS z-9z@6*BVWow>%yeRV8--+@EN1k1Fd~H@u02U$xd;8F~IHz;Q8+aV2qTXh%={Z!6b$8oeYozP)4xmb7z@V>61NdKwre)VM14x_L zT0Mj}ef>(yk4IT%ZYVF+o^G-;qACMYU$t=OiH}=>zEe%IWs&j=2=&oaKEy>P#2hia zTrAh-7`sWM=(H&47nIpGDmE;$vllp_hFd~XmIS!_@^2OG(QIGN-dEmbB3_aed%B4g znwGDdgIaUm+>SyBM#4+~l=C(D@7Q=5pGDLj-M9PTo3VnQZ>R$D_1zCE=FOWnIBnMk zDJ`YRVyzd%MY3`Ss->F6dOG3^O*~6?S9MnDA~HOXIn=4XHC!S?X_mM#$ zq?Is3)KNPV4&&XwD*JPDb3eFU&`G_hr!z6>IcBH%| z-6sDA%YQIw@Cv(g+9lXFx*YksBo<` zNPAVsPfDqdOZk%O**ol{=R`91v$VdWdek{{oVY2~2)SxFBbilco@1##s!*U|vjn zG3_kucnB)z!;!)1x~Rf1{LA#ek>GCr-^zE!O%B9uhmGRe8>tZc&I9_#tFZ3yk7IC0 z$BMxS-aK=xL91E{ol;vy96_}D%cF2+^tmNUtsG@)gwC%yP!NpKLsr7LO`!`~am~zl-F)0R| zI9%54#Xq)5ziwzHvloPVb5MA7=C+W8&A^_S`$r{WMO~TPo{ba?pNR0Y6MYq$(}!&+ zvUEF9d9OUZfO0Mf+xYI{YM$7>UsGxPb=FEp6;JlArv!J;a4rp6Q{LX+cF0HZ#VD}Y zK=?o|@Xb`W`l)KSAbM%oD~pORhjgZ1_S&t%)jC(ucIvJ)DX3mH!$#HPM-VBB#A4}= z`Ry++7CTm9KZ2Pgd@n_cI_QJR0wv^0FcM&2e(%*EtuGOQ6mfN?8==!NjjP_;4=bHpDLz84J1JbA_CuowV#7z4=&~ro?_A9PxkacA{A0w!wFct(SSL}z(gm7-;Q9E4 zEC7r1)lyVd*cCk4s2Qc&m+hzh$nshp_0euWXFn&}?Rlh)If-2JgurMkt0rFo`gB`5 z_L>h-LgV3!p3}=ST4*c6FXTsFpV?zPQ3fa^#- zsPlGVU|Bk>c>NAg?e0tHRXLQ-)|>idEj4+`SWnVr`}b%B+IW+F38G3>By=JXrZzsW zft{PQe{k=CU;C8=LNQe{!=*51^)r zf^VhteDNl8cYbGRajThP}7&+<9zy`+I5(+*+%MQ=nlbr(LBRx9S3a~A`=r75q z&PgO@h(zr|2*r`~IH}JNU1Z5C$Ya6c(rvEl_00L&;#u+CQArjx2R|yzM4K|HVMJU0R%fnKbcUe zf#{)@Yl9K|R~yg!CX(hEe(_N~jSGb4K1Pf$vf8Y2sC^98T#FfEPtpid$VJB^ONQta z$$IUAy~}=VvZ5%WD?X5UyVdKw-@5(d>j8Y3Chpoo@WL06QuolH!i5ASJs3g6x!5lP z<{vI*2;=+>N01x}svNg|Jm=h6v(WLD@Do>WrGK3AKAsu>!m|L`M138ME<(&Q8-126 zQd?g=tdd@Q$`qE@tP5eIz9Gmeg_lGgwWT^B+AKm?sk@PVMVt8^-?WrHf{#3(u{z%zUxdC9`bIoE z{j@ZSfM9eN-M+IbF&R+3h*21-w95&uc%a2FNRPNT_pNEc_kN3n-_4>auO1N*yh8<# zrplheP2&`((e~P_5*tGMAcG6-rBvX|Rl>ZY5KU?c~CX;9r{Hng+$eo#kQPV!ghjDJPpegE_Xs7m? zt`i3f;J24nd){LNc>j)v$F6Oz%pQ3M7`b6R95da->2AIQ zB<4l7Yf6%^$evgpTJm?E=u3?OM?OB}w&TW{q2=yt*7)vnZHjKBOe zYXbeES!(27Y;5NOu}ncT=e$>!A0|tZf>Dck@$2j#to90VW*a@^Y;4&zHHqIj_+r6qktdl4MJu8=4vgb0|gbedkb!t zKOr7!)h2mF?H}igHMHkXf3WLJ!J2_x+o9u~6cU3$wVYPq@MUdg^Y9r@M~}ypYM@4j zQJs$*_)BRKqQ;uW0BU}UaT|G*bh;2o2&f9=kwAyfd3bw(@Nyb@Rg-g)Hdnb4v780g zjOh5dvoxp3c*CYj4;07>5qiUBM-YBcx!Nu6l8`rdOF@KeAV|*8?17r%q+Q>t*g@ATsSXEQ4M?rX<7qk^fU6t%a{;q`^%IYzC&K<|6C>A&J zh}@(ISTT+2* zu8PA=>Ozg?6|$pcs6|kE&APjYd`+qibLI+rx5Dw{wy5FR>)J_KRvP5ihz`MsErnh( zP*ONi=$1oIvB)RS-?A^ZH#lyJdWlnxDQt3{O-AD;y#}OaS(dsKV%yR>Nmj!)0=}6bxKau7OFJJ zPjiAB&F6tck&&wRv(y=lo!R}P7nI!!iY3tM+cRu&#o{3n@`@w3Y5}(gX^?J4L zahhJ+t)1!5pOY2%D{MCtZZP0I+LF3AVS|I#=&l}}!vcqnP*mB1_(&t_QEGzNLyT#-{{g!2=@L+}&OPYZqe-2{B1^S;RZ0F1kRjl& z_S16E?brnYj7CJU5wsZT#4nX! zP9}}vYo=9&Tbqwe3BIc>`L7=kot@I{KB>83fA>0%YL;NDuJ(@hc(;s(FM^3Zon2?s zqCVF5fTip0`!Mfg0+gvX$ZDi!b-l6gLKKo$U{VCmx&ye3a&$~vS!$HeJOK>ezn&1# ze9sh&F^4C-G;~+A@BEle?7s^1ciV(; zR;0^_cU%eW^*smp8c5liWJ0PNR9xxHGuW$Pv!(C)=FRR?LF%y-&#!xlf%diS3j7#b z%q9s+c+{H(oTpwmPDYWmrP9{XzbJGuo=l?0eZDSG;+m^0RUcY0L2el&YAdk?u|!=| zODDN3NfMq~j{7D4(wA>&O9mbecuqD@nK{{tUQAJ{Js-u!k}P*ajUcQWyBg6^za9t+ zL9}JM7ae+=TYK6&JC(Jbfm~v@sW}{)b45(KNwHP$PYTQhqWCap1+fw20k-tuveS_! z1Yv!BK#qd%DQmp6$a_N$!reWxgfh$>Lp$b=8`TLepbU%YOa4&)ky@s7^>#<~`lhc$RL&9mGuOUs?G z2Cd{CbC)o!+$vlfpoH>jzW=GJ^b%~(OR`p(T&QoT=qn(4`eoK%K!iI>i$&?2C7IPv zcYls20>wQ3vT`fww5gp!DuTHy%gmdX=gN>drv<*PQx*eJ31~Qxb8q>4vo;ez&fkF17Ad|JjA(>L^*q!WD6JY6yTV5p1N(=a<8L36K zGD%(NjCSau`Hm^|gUro?$M*J(rP(>t8Lw5zHG*80ZKRNjW%C$0z;#pPfCNhxPJjL+Xu(qo7Q%1O;(NN2>Pe7Wf^4|D%R{g z+{%q9a$>KQb}2n3fU2l?gmf~!LAveI?P7OdQDy8T9a4>Td0a`b_lY{w5mk4z)QfEp zcN1+)4f=G<0-9Qa5GoDZN5^T8EixTWr}_spa#QTRPq;-Acy085EyXCIe`XMJ*Falb zw2C$gKZd2f_f{H3TUA;&Cb;+~ZxvMiL3}2kCotDE$w1^_kQVQWv)`sIYGPP{Vg6@> z^r!;S=YT^H9pYqvQ_xU-scKPB$k>=wraJCWn(nt&ynp=J2tKm|18*;41#vpc&mRo! zSi(M8QtX)5YaMis(HBZvp*wqXJ;|8j*86mt;Q=Wjz{o}dUAv>lwz}rF$kDHH{A;9oQ(WE+=VAfPcN(foS9l#Flub;**@pj`$tA(Yt zWWx-gD%7<2G3%xQ4GuRCbJV9NT<#MWQRoJ{z=#OeT5rjX+iKtX{6>i@{=^rHUSB1C zOEn0Pf{K;PdC6j;q6S9{l--I~b`;6M!CGidH{>^UWCc@NGe!EZ26B?0xlRKmN5hl6 z3jXAm#-nDUZx#X5Q8TRu=qBXCU~UO%`xdpUg-u@R!7anGrzbabLDKD)i---+@?L+& zZ_CSriybo0>G*GW1k-wvCCTB6u99-Wi%W40wRZr|>HSR{?w5%fPSR3mA)&{+&ib9h zhJLBl{9~SfS2zV;aOSWMzkYvP+NaP-NygIl1pyGX$C}@s5D(>(!d;#Z<*feW$PK_>g+OAWOSNS{F3oYyE$yLS1%98b^ZS33yN&i05gQI($(j?#iuCvjoh<^cD8o4 zyl$yFq3Wv5HqsIwEBa!ha&q8ePLy2ED_7aebz5p6$h*nah7Y>LDrh+J+!FTVyiBc% z0Te~WiygU*t+dJP!!4z%I9@^xvE2E7B-pDW*$s0G_g)2g)*rWBnOXReHh#e9WJ6mzjL=R{1Mz)Y)pcnUv&78X1&&etrAGK z#y$*Za3CO%9T{Yjj;U|zeJnsv7tYav#Ji}iXK1W`)i<^@J>`v?ct7fyhpWB7E0Evn z3m?&Q8df9WM)PaJ~zia*JnqYrRaH>^N8=Xp6jO1&u_o53DwRrwQpPwkF>40JRl(ki zg}v3n5WchC71gsv^}fUuM~>$jz{W}h$lLVG&r}@!u5(WbngY287o3-xz7GqOx{SoV zG7>KnCzPVbs52cj{_Ko|W1}@gYaj|pvfpv6Ae9LlCXcChrBGQ-kC(GS&6=bfy=CIW zmq`bMF|ou-f{Abn>}#>;Q+RqLPzC;@Jxm?pD55RZz_R#d=7skuPfMi5aQt)x-wXv` zK~rBc`)bO{+(pSfptnQ4E7PyW$`;JlnXYU`H*4zECEbA|hg3G~diuK4Va^6$3MhxF zM(D*#F!V~79@LUGe0XCqdC{?8ZJwNRSvG%Q1`B<0$&9fcg;;YoFJMAbB5A*d|crV zY#uKKu097n*Z9au;{z~ZYlSVa?gliM8Z?ZesCH7`_u zV!kO;p6jUjlsv+r$Fi9-*3umSZ4xz{9s=qS!ytL6*W?&aw z%evlX^ah;obFU-mf1B)A5*0HzR9z2jptoq z&76zzKk}~Lz;5g}p0>7{{*tZkypCmGO?3HnaD%bN5LK z^S?!JI26xIKXA809G;yhH z)gy+3k(NqG+a%9x;ab;=4%k-gc!`S}Yf-3B+sele5@mnRz$sd!30IIrQkOmWlSY0s zbout$Tw<{t3ioAcmhSR3t3;tWsbToVkAO8ZI?hUI08c{XN9@#h-xwtP-t_=K9d1Jt zeo;_qmx3)Qnb!0cgq@h$FN&%)F`Ho$vlE)?!ocP)&^@VUpIFG48jorO`gsJc>FA%8 zSG-?#pozDhPWjha(&a-MeZ?%U-mfVlW-S%;Byr{Aw{mD-l+eyZIIZoyk#}qEf5!9b%??bZ zRzMy;0!J0?xkR~yjztWN!A~J&6>$WNhPsnNa|8?FgxC5@fh;as(9fI9>E!E5pqk|T zckSBdLQmt^q%?O^Y41P%>KDYS;GOSJ1|4cjG*#eV>ZJ*A0M)r_@C;byZ+FDOq#n>| zdhuqk8-@L7PARnYJLco;OGgllDdHX4kfEC5ep;((ZaN{uVzXODxc%HkzSEh~LFolV zl(F|1P1MNRnsDnJ?6(l=vA={F*R3tUt-8%^y~yhLfVG*TH4YOBqc%* z`BKYrslUwL*U7cb!B|S`qmM5Ajgc;iZHlzeXvt){*5yp_@keSg;W;7Tz}t@5Mn-en zp!o_BIb9EvD|mXk#0H!7%4u7O-3R2SGKmH?gQ?`uWg%Pv9LKli*haJjjKGvNbhGca z`7OJ<|FyUwYt&UbmutSm`O^n{BFWJU0=%Go4i2Gvu3mopM>YNO*BndNhUI4Hq+fRc zI1@@Te;H_?+E#C96V%d~%U&vWwZEWmqKao^C8aCq+fHNdD>2BMkXB$HxcN8_ir!zW)6Q0# zJJn=Xv+Nh01)HW_>y&vYQuH&sz68w`g}!rxUi|)Y6nIuyXxQDUx<1J7{E)V#BI@nE z*H4&C@cd3nk+!3T9tv!qA>0l1)*cqLja|G!mJ=YF1M}-CM_(p&R)Cn?gWUjb6Xk10 zboQn|1a1*SRV_=?S|J3<)3UnF)>c^c+Vb*#`sQV!`1ldZW;>h{jbpRGgEU_5l&A@8 z!ut-BJJ9o%8*_`Owo>=|{HeKI%PvCL0jPlnRp0}bQZf5(>iJ)KRp)^yY zR;XncR1e!y-5qZ3#q^_s4narW<8&^?GD7OdpN+D8)vLap>Sargu9~VBh8y{%7%!FQ zsEmLAZqCA@;S^wBPp-t--!~u54Pp8mc*+cR7;(^OU+6Whbn{J~Sz})7qm$SDWK^)N ziW_yx)t&(*oZ%9Ct?;CCZF}H8&>Do8yXThZQ2X^@xmzd?R6QnDSlwUbT*nNIlX1wS zmgUlTk})r3ca4b$n8#hss=sDH=U`ljNJ<#o|0rfuP0-w%xy|rep;QSlQW3bQmBMu#sT%CAPb%kq`8 zzhD^{h_qBkN~Z-h5x85(_mw0_5DK)-$c4%NYWJ75TAk%Qpodb?k^-wa?6ZeQUG`v+ zml31KD)6n;(_iUHQpFNiJezfPo{6REZh;qzJ!uT3p~0`qU^f{-)Q!B(Fq#naNt`6y z)qSWUemKu6`WYJbP1SKecSD%@_vgY_?b(re6z*)tBsg>oIpu_YcjAorrC7wBRK4(9p}=ybgf+ljvtfGTaIvAItrNCP{6nqR)}EC zXo(r1iq~YFXQVB3xcLnCGsf^%&*E|m91DsnUaq$)Rkzg$aYIv`@;L;g+kAV*8{vM& z+BJO9BMqV7Qg82HGb2}`0uw$T5ZEjoP0AnuQRTEF(X`#n8|^=VqD+QF*9lTYO2s@zfmw)X~HBJN+y7g{a~ z9vA8(ZQ&bQ!W|m{TJ& z4g131=W#6$84U`vDR@3uJxVPv&i`J9&e}e<9FrZfL^o-6%r~`plUV9FHT^IRe(ChH zz&W3+7hVkG>xv6?GhXIP1^CP*KH&;&;XS&%r;nUS2q>YNg_Ei47O=Q)Zo}mBm7VFC zJ3{Q#H0{>`;>D|tJ>!Z5x13;N*yi~t?0Fn>VT>yiNnvPT-V?{QnF}{=QJpkMt<(U) z-u7}@gFo`kwa1lB5!n}XkYs}S4&K;^+pzI@G`#~mkF@9d+Ti$34{v|Ya=5^?1hP6# z;xLTvxAKyg#2mA0_q7QVU15j^$&U-Fjgxy;wyO7Aw6x1wCTF2Ou-Sa6M2?QRl8K{3 zls%cD=7OX(uN=j(<@dHzG3_3M4yd?ey(u`m(2cl`>i!zzhbOowee~M)c+)lm(9orx zNGMR4+{2_>FW>oMh0fE9dM{f}U0kbGF(W5MEeM{goZhaxl7LwdZP5PKS>xS&X@#RL zHXc5Q(t^Qi$#`!`k#$8O>;Ef;2Mmu`RrCUNpUWp$$qm$@8eetA9*R0QqeBH-WEF zK4-?JAY4=VpmgGq##pEYx*FaTZI62T$2Nt2^ms?dR=4x1wsuWLYkPbDm1EXs2&(L+ zJY7J5_qodBtp(s*0_Kfc8nE5(ZFo9+2O!F=qutDZvv&v3R9!6g`^JApb?@HQY;~sW zuD+vO>qIXjW(s4Y; z3)Jy9M;=)`Z0|*$a~|MdAU3B-oU;+4+`q-t3B>|aye}vCGiC!6aF>7&8?MDx6d1rU zHu1wN(iRPA4WQ6KveAyLumZ+yFz=Oszg7iN%=oaB6-EWb?@`3xxMo{$L>bqvwB4u} zr6I-wW(`M|=@-mrooEaMzoad%x^Q}n&zyySeiia0h3o$FOp?}*5~opHG{3YrEQZNQ zM}%TS=}ICl3X?;PI=YG+U6<91pQ@TtNv-hN$uPG}6WJl<5XI#fbw|SDo=PCR=M5;3 z!yiaD$qS)8AQ7aw<7&~WgSa+wGll6O90!~=9L~DbYYN(7 zvHq#86FO25mqR1 zB= zs5x~MJcM^ci)cHV(?WwY`CucYw26j8LuC{2Zz+NNO(f>#ZsX>??g)7f$m9g<&3gMg zKrWVIczub&X8u+0O3k$^Dz51LcUC53aaR5J?uPyx!Q%z>Qnx%hx}Y=b%SS;|0nOU{ zlOJk*ci&e5NO#}9hB4a~%_DOR_i zlVP1RXrOQPy3*WA=m^{tAC3btLpjBERKIiOJ=jEl>Xq^>AklXKFMEL}lL| zWBK7f;VP)yE{Tbt><#m{seb3CBN)A&tinG-%BvZPR~E$+5VB{?{suvc=1Nn2S(GLOpz3=jPn;>!#4=5-|1{%D7<8>F8$v3Sp*s)j;kPz!XI!8_IC^6 zW{Qn#MBzDUgB^2R5mm8nvd2 zx0C!p2|vJrT3jsGdUbt*kx@e8RUxoY3oVD@GDG1v!;?Xb?-qdywT@{40r($Cxh$UTx#1o6L`h!0JRSx~fZ3&Ja_C+&-g)K=74($8^y)Cjj%)_#{T z_OpVMt|nxOx4wTb*tkuug}F0b6a@!6@teCHdjJi%MS-YER^`cCL!5Zr)WMZcTXd2Q zBopCWDEegP(dCt36P0JJ&1qy(9^3=bB)(pA)J~%hu}71D%M_figKDRvDnGlmj=ExO zmeK#VS^l+K{s$@U7XR&w{y)P74+9n1z=sx}8+wK7!RZDAU+OO|=?ph@1nVvF=^cf} z=y9T=#{7)_cfP^@(@*&SYntG0>0hlDTr;!97a<_>nT4_|AQv}G8Z}F z5Lan!1J6phf?Elt0L1#ed-wy?M0{zw{^xJ~{aroTtCm)8PV39f9i4{K?0iJJShZik z69m+!157u&n3^llAUjHw=8J?aXK7$!%gLKNv&J% zO0d+0w1LfcoX5B7KBK`l0|CJTmu6EXBQ_xE1N# z(5J>D%iGG(x`^$N$#rI8BLAUxrxX*+f?Yg+vZ~)`2Ywav$XY9owOro4FZ}Y_23Z}g z=+VSFJFFQ-R11=_KkTz;%tHe3C})K}GmA)7x$>&paV5V2Mj;xS_rKUy4ldf~V* z;41v;<-jYYn?BG>j*$RiV|vNk9bH@%zh^KNGOBTpi;APa5@B44$oT=g*cx zWBQ|dm@RgI01{D$PM_H1MuS|c(1s=`qnAP@H?@ewBhOK#mr(tk#@F!Gf2$=l^ zNb|*5^Dhhd=mPos|PN&}%cVh1K4ZL^n#0fg;TV4^GpYZ%W zb$=ilzP*7n6fTprHasQRpHctgrAaFY@`h7E?CDvi8Y@}=F zr|FU{V_V6q5{h3DG#KTlmjzfb5J&fb6Ga-l(Ds|&mtpj5&TDinEZ1rvySYquk0|4k zpc7>~!uARYjz>@orSgxom>;qNzBHbeqp14wcl){*I5oY1he3)imZ4F-N_+3Svsi7O zz1AlFHqzeC77tVre8p66VZE?w)s{$ei1VhxHM=c}joGX$+6-q9x0wHUjt(M+7V6$g zyJh;mNfpYXGSW}efg)>cy12^ck=FkTv(Y1Ya$ORvMu z+^b^h`8G9Ve+dYArN2lOu%Ty=?x2uSGrL!Hmr=iSO^$;7ANHX!K9-I@;)I^R7XhmE_>Dz>8+u3W^YBa!C8zo* zJAhj(BbxAlQ1TB6$`&p>xP`Bd*dqI3Dl1je1QynhTYFZpX4cue*sc!k)3$tb+Tf^< ztNXlnWRj4wIyd-RU{JUu+7@}SGr>k5{s=rTPjA@SiB4~H{cP^>vi(yIuCHZRXRfhS z%*PPhPsYzaJpDRa{tfWK>Uy;Hq`}Lxk-M!ocDtC`Jk&V^*>hf=J39>yRH^UJ~iQQ?j0rI z(B=aF9v>isNFoVRA()_FHmyF+i!HT932Bc(L%n4Ew&+_|7ehvm6z*FCsXZ<)gjoS5 z2sxxI=^^O@OnlP+O1xYC*9s$j&5ua+A5!3*@3n&`mo&To;aQZ<^*_=C)^7Wt`lo0! zJ`CO$dmS3hzjTWW(f{Atx%O}<*LFY7spYVQNJ7Zjh(U6gq-jV(Vq$VA*$hSrg@%z( zjT{=uLMW7Tgh5V&HAqZy$e2+MV?s_Dg>jnM?|1Fb_u1FA_Woyo-}+~-Ki>CxpX+^} z`+1)GIla$)|L$LZq!??~9e102$M6B9Fu?t6-01OUvi_Grv9`#e#gCm6uK`rDLL zbMu8Mi}NMcb~GC?p(HIIKek3aGBZEUICMz$YE871f{bUJl)NP!2ayX=gxU8>A8j(D ztUhNgc+&UNOTZFV{Kdf%ORd?)evVM8U_#C2Y2?j1UaKU?;oDP`iNx$^s z#FvfPl)JBn(TUrhmtf@j%$qgK^C$PUiDnmQkwb}(Om5SA53>MRAYA}Q;BRE|7eQ$O z+Nomvs5qU8D;HskJTey%iZIZf%kI_ScFQeTX=qmYd_e6>tN!Y5rQh9-YNlLv zZfZbU9lwhF;L{VE{?PwTZ#t`>-AtZY{s4?|pqG5pmqplPb;B4PQ}TQu5O;BLRBu-9OWi=whq6O&%Ad_j^Z2VX5%Umn0#f|ZvQ4x^KjpN=|x%tWl&=PugGJX-8hdO9Z2 z7=bGN<|beJ$-sRk136QJ4-?JNu*D0aGh|;H)LhMgjkXZU$y891F%ZzWmqIT{@^7@C z$dMlL&D75kfO`w4LLUom>Y}DY>W1y|=1mz+T3gPg4@?5-@o4U`wk5ZP0WJOgB`}dR z>5*`IPu)e0x~;-IlyT^X&r@&Ds`BK2YILXD__eQPn-YmZ^nIJ(^o_0`A?Zd`I-eu! zhMAu-{LNY@iq90(QVwHc7X+D}ohO6<_%6o0cqB{DF+-zd7#%z(qYx6bUlRE+gSLle zRT+trN(*>oSuP1wIfVq3YgT6!oK7Gn>o*c=UO;i>nHL9h2O%Ren^xbcS?qqT01rIx6G#F9udgo1 z^OfEhfYX*VJvs+~#UcSEmHM z+D;&_WXp=#K`fXHcdISwju3dLuNo3@vgcPuU30A!-YDZjvxh=}veYl)i;P3sS^(%- z0&~0EqRhNxR`6!CeC+`Gx-}9RhnGD9!I2$fuH-HE>tFCxcb7Brf42VhUmGU-_mEpI z4(0FXh)T`!J@2AViEOHDsk5^V=AW5nbxSw^)JW`*8~8AYVAX+nL*kF`D%(rgwxkLm zgsZnPXANK**h|a38ze=%(!>Gfgh9XGV~a<`t+68*98j|e%juK2z_IvMnX&b?6gCSw z0Uy4OogTH_90!oFX#10Y<@-x7e~p*_VLnKRCzFMF`zpORTau=cKgZ4ajm&&T3OOLt z8DY=#+?N^9qbLOxW2tgRpuL^_4!w?{CU){2mI7y6JE=D%ZH0+!%y2+mzU{nvwrBf7 zB5pcA?<;-Pj2~6WhQ;oCf`c|Qv~QGT+Z=R?FPW?ALgzW#L}(r}`H=kL<{Nmo5l?P; z5UmL@p8Ymxq6|SYlds}>HBcSq?FbENYGl1BEhy!6UVmn=neJxL zupxHd=jXb1O3o?+uMb@~)ka7#9)`ECDE^WlL4icR%dS{gE3~)GnXlI>W6KtX&rQ6Dt>sVD zdsZyFkSZk*IGN(?uCld~#Abt8eaqP1OB~R5fEp&@z&@Fc+wmq2`2Y`#S!$`9^RVmm zhuS#0B|YUv>t|f+dANY$<8}))9V$w7F~8zn>}rnoJ6<2BIu&BMC@!iD6WBYx|A%nI zoD8rpWCNjbW9=N!K{MO+Il1jEcV@vYNyCtGaaJZNMox5=5}rMzZ8l)s!;>stA$(rY zk;g1bxUB*ex$}A6ZXt+$f-rCwFe?BJ5aZbpOwNxX=q8IedGgX(wLi|n-DYpSt8sEW zE&eDehI3D0hXc@H?13$xb?9^{c8!Vch^lyUVQWV$d{++8VJ=atgC+>*d ztw^pbsxSW`H|d{c{nd!S4YU7;Jz?KvA~|{I#9LVjOaGjkx}fKp*WCZP7#MxYzjez< z(+cWf^So+@#Np3nhb!9?oZvz~rq%RhSuxlv;Q{m%AIQ7Ug*faoz0I=-{SH{nW94=y zKwkEL)?4$ySH4aUr@qi^_6C1uRwnh}KzRV|g}@HD_ur-|jT!7Ok==4KCa%xFZLm}G zMo!lcx<#g=ZWmIW0agfS#fYpYKa@$cx3XR;8UtY45DW(tgbwlw(#m4k@-7*}m2Rpb z;0|$44)5fb%oztk|7GLXD35PxR?cieK*c6&940nx&dMIK+9G`hYb)UCkmVnZ_YR%E z%~kEm%fNvcJ64k!6Af=ZHqje>qajbT$9(3NnukaYEJ75-!xN>^g4xdjDVnBj1CZZ7 zwA;41?q1cBjF8w5C51@Tt+R*e%NOJHl~loseD*0Vj1`EOLvDks_rw|wVyPYQ+5;Er zKjOcD4wUG`2h{@T3_TSSOiNIw3%#g%Xk6SWJ1=kSn?2P!LJBshH8gcd$2j*tt_dVQ zD;ob{M@3O+Dd(Q*RFiox*vh+4;1u2tZ>lo-Jk)@rN0b^KeyFedLSb-Vw21sY+uSHK zufc`>feQ_U_(coIgSS7OrwuN51UD+xt}rw1ZWYU;dmP6&6OFUt?@ zweFW`cRBEokR(C%WgBFVIHZ_YSCif#e~WjW%SfGV?D7t-)GNK9X7Nxed0Jv!T{=o# zuyxiHWl>+E{)VeQD)jht25%%G^!JX9wH7kirkdsE(RbB0eiS?qWgVI$DN6Q|qw=pD zk4@wH=%M4-YkqzZ0zJfXo1?SSHdRogh{X9wM6MT(T*K9~FfsOB}rjD8# z&X1{+@DJg`WJ-q8@|m6}rS+2%lR4GmH093LBwQ8i&S_gADzx2H2MF+ln>Mu}t+$h~ z(?_~|db!*U!?^Vb<}^@;z_f0a!h5lT$B#P&?%Cw;_?HA6$8*-D=ZOmi?0Da`*(Et% z4(MI47YBrf{zM{(cITq&%ekX5=!x+YS!V_~Ah_1eYKLyk9UOX=N1J-MHs!%df52!QStXeaIE>8U-$HMU-`5{$FYz zt#lqQlX3M%)H02okrp8Za|oIc1HF1rw7x#ekv3cpU-Ob``OG8AHLbs#pr({X`Y~tY z$O9bjg{nqoGK>fnjl>$CX*LB1ttu4>nu0#7Ez{mBT1UGS#c%K`9 zmq>lZSk|MIDW5L50W4n6MKblr)`e!}R+wORoS!-&WOwSG#g04e-?q;E!GzMUHa(3x zL8y7&{r0M7op8e?iQ{Xn<)QaU;lD67i?Dm+<`;h@iURn+z}&l#2$k)I7aY*XQ)6rn zNQKq+-%=Fv6T3qN{n(Luxouu8;7@ZIn;^G4fuX{<-v8@Gd_wk$`#9M_rk2%i9KZD0 vc>lM%8S6A0&y%XKo0PPmFLl44pJxcSC;Ae^?euo+$$zGb|F^QB9O{1pi|d2T literal 0 HcmV?d00001 diff --git a/docs/images/prowler-app/multi-tenant/edit-organization-modal.png b/docs/images/prowler-app/multi-tenant/edit-organization-modal.png new file mode 100644 index 0000000000000000000000000000000000000000..e0d28c727d870d77d410db4d887db63055483815 GIT binary patch literal 13031 zcmeHt2Ut_h*6xN-1w@c0AVH~0Q+kOYASECopdel89ccm*iXb2$y@((nAV?9A8tKwO zM0yJ~p$SqF1Pl<88~wiXo$s9g-v9jnz4x5^+~+wfnLTUPo>?>R?6qc3*@P*=B5+1a z9jXqHkN|)t@dpr)K$4oDqa6U~=m3`i0H6ZMNZ0{#B1g;uD3Wme!K;%90-#@VQUHi_ z1jv5RbBh@NB%-!oWqyl6Nf7`gQNlUYlABcYHRvxq@R4{AP&QD7LW!|~wWqDE zo0o&TH(?8qy-keWiHV2Y5~5cCSrw=b+0Xij^o!^F#hw{E|9mAv$fIr{~I0E*71K>?8txS|W1YC&PxB)0pqctE32org6;0iHF|LkjG zSt9+l5C1B2&m%t1eEDQ%!bgCC3iwDW3L?1(kTQ^f z7)S`60GOzUoa7h%MKK8}h>VjI5lz>J2q@ z4Na()!JWH?MnrhlHnw*54vtP<-ae0f{rn$?Jq?eDd=?d*l$?^9_9FddMqd7#g2J~& z#U)kMHMMo{5A_Z09i3g>J-vOOMn=cRCnl$+5lGb1^2+Mk*Yyp|?)Sa@gCE$#qo24) z0MKu+h}Ykc{T(g_A}&%gG7uT%Ph2FVzQh1xAS1tUm4Z=OkMe=X*^A;&sF+j|b1U1Z zc_j4F%vPSmr&xF;k$jk+(0(ENuK^4F-$M2Wu)pG(0aO9fUj!m01(Ab5AaV+FB2iFL z{3NPVRKMud??n5HPX8qOKZrn7LPFF*Mn*}SXG#E9<;O#rIVJ}=McWLxhj&9J!?-_bF$}l zUR+#Ol4K>tXgHV^!jKE&8h(wIl*W8(Xeq1PHuocSZAzalX}hn?y%@hxzvkNufCSdG z0K(93Ag@^?HQMW2_~thzWsYjNIMHhnn+O76G+uu9P4oy|yKH-R4y3A|N7zHXshaB} zqkQW*92eS~3sjFyMrU@rqE5ij#?byd5#My>&G(b%D0caFVe1o`e1f0O+kC2HPO+C7 zfq_EB*kKCTEVT8l26!z-EE+jd;hpj!^}gw}chqu{sZ=WZ$x56)ru5ADrMtbnMj}h# z>9y`0S_r)dYA`ws&!BTlyU4X>fPG72W@l_$;tLO5gW!czl?u=`lmD}CY1xfZ?TuAppeK5{bp#nO)+`sZ{mt>_4BX&YXsbwujw zMX8ot=IvzO#Ii37dX5cXqk zVVc8XHI)pn`_8q;YYDR|nvdZ*aVoIWu9$_=(yaLWqw_Y zOrXZWDz?!Pb^L8W>x8xQ$UX9cxw4CG^sz@YmCLpr)Vl8FqEVc{^pEL)jP)idpE5^9 zMJ)MZ4x=BvDf-QOzZG|38;oK-S3$`$n_Ydsq=n72YBi_b%kuRc=Q@_;dWBh)#6(-p z!<4JwBceO7t0kswC`!$}Y2K|KwdSs&lmelN5~L?ts1jhEq#H%3KR z9)+rCT2*;)b4DQRU(@GEx<>>vLNuIS%yXd&%Sue4pgG~XI*Bi_ZgInsxrtO)OY?Kx zo}@mJBfBeh%8#{sUZF8l7p)Xo3qCVv`t~KSiO-u!&x^tSY0OrX^=uW@rajr>=(kUT zZPOuA@5~(&yWx`xt}6~3N4(TTMS0BtN5@h4 z$;$I$@=oc4q<&%XK7pjDix-pLjhv5uLu$Ihi80wi=cAJNYk9B=#&^&QxNz#xZQ%W( zF9CRyl~aFsD+uN>sCB}PohxxtHh}3+5bw@VxA3UHO<0!F!XTMPSdA2!F$_!SRT{){F*aa`YN`!F057r>HgD z)|kT)@q8M=wnw(O$n`<$$Q&IfHQ8!k0dmYa-6VtxX4*KCt|;y=?Lc1hkSvXHp0<6C zFf;EsPJY85#8?h89Ff(G2l|-@He)bFVc4zgE5rNy&9P$nHOFjm-*3HY^KvuzlEW|EqY$YOp=g$)M*u=S z{hU>6u*E2FT#y967#&Ve0@O$7P6zpe4$h?PY?GXlb1D0>nq4Js3fGAdabf zfi5)}$ElUzu8c2qF-ljuGS^N;8l)MEk^0}mz7`5;9 z(#wnI(lI81WDk`g87Hr>m6Tib6@G;aDDdXa(lv?eSXS1srRaIo(Z<==rlxN=`0GAY z2?@%O;qs+7)m3cn7kx%sc7oZlTKxxt=$(k#%q*Fk7+T*e8-{2(&7F&9RicxNP-=QS zTXYEpF|=HcQ=&mv7O>#%49iHDCd=Zl?BUsAMRon=D$d5%HCgovR#_?PYhmq`U!A=JSr?W*2OL=_X&%N{LDIzX; zkpM7F%{WX{Nn4GU<&S@+rYqTtmWt!Ot44C2GVWGT)nt?9!8Man6l+I3jX5?MDekBD zz!=ej=Oh=^hH9kof%{vBeGX7qPBK`%*&E^#`--uHrw|If zq06CzJvzyhq7OrGJy{y0$0qgkC{keLk`&In-=a;-d=|ApHhfitGvtyi@7{w~#mp!~ zPsbn_8=z5*Io*oP($yKMWn@8YuYU4#T@w~3^K2mVyuRcpb@ZrzQFnR?Y2OYG0kiF! z%NS1ZVZ$9!fu1AONe2sBqt;-1o2*e!*neNSP4^lDU7)d1(oNLP@PONA{ zksbpHGLI-O!PZTD(|%+xVyzf&b%D>A!#X_?4!maJb<1n>`u-MWw3$Evs0e_4APAKc z`(|Ph;~sSjTT}U_H|-HaR4S>ZSqrUxZ)}6qWg2h_DAakS;w(%C8@1RdWUk$<$TIFN zq_8cr+FF@CA@^Z$d;ZStS+6#!qqe28;O-WMVI}JYdS~z%A38dSF3qf^lf<0l%y!w@ zlf~@2Sd)x*{nIk5=Y9$bPnO9_jb%x&{!@TX>T zm)ImW73@yReUY%NFtO}7u{1kru5m{QX*X1UK#N5;L5yxTY4;j$7amg^Fg+}NX`IUZ zMg)FeuiveGvR9D|W0QRf%W=&5t>( zUtZg1SSxaH>f7B+3v4rbuxr$OeO?Yt5wBSLru%)B@kU*pc*+Mq+}9BesQSW%Ns=hJ zMRsgNt4Gth0-P#(4aWpVS;hqMLA^vH9gzb8_uy$8-v(pw43nv8Q#X!hHBN7C#m9bd zPw}#hl)PHVq^EWvoJsFG`Tt4qnP%!%mbqmZRC?C#*?a@1 zD;f#)Sx8LOvkQXCW4aL=e$wtFpE0xRjAkNZP;trt$H;kSUr5jDXpHyT7*Gp_kZfV z^ks*~Eis0R0@}Cqv+cCmDZ~ao76@0oj9qF|WX0%);Ut2D_jb;ib~qNJ1QEt%i&p)N zpFUYg@+KguPRqJHH_96R4c1R+|2IM~VdVGT7OKbk=dNe$Jp23@0ci*fFWAn7=(WD! z?X!00>q#jKgMSuedQVow*J$*{&%Rxe9SgT9EpV*EGc?zZZEh|n&1*+(EyJ6k?+4Cz zRw=#YP{oM@pE|e5Jss6i_22iIcOKKX>r#DdNDF@}5Mx*8&h+V9;W_VxR@z$+90h0| z!pe5vL@}11%qV-Yxm|Y5p?EWn<7yGCYHI$}Du4hofi3j3P-|dKd6j zR~7tJ^@>X#9EoRXKu6@D?$sVQ`tNg0315s@(>ax-H4`*~u91<@=6!^WFzq9cxm>c% zd#Sg5EpgcL7IEqrkKT@T^eV=t{V;-8C*K;ghnvO<8qd9(pgX&Y>y<_M4Y_+7oK29rdaalXQ%u8&Rsit8x z+01GI%Q<9QE*Udw;}GR#zogysdZ;RGOK}GN7gC*~@eggy^HkmDO{r$G*#z4lGT{&& zsAJdi_V*Bfp5jEl-7c-fb#NX>L*~YPZMUeeJ2Adb|b&D_-v{guHl+BSY%p{5^y=1ut`cV)WY6VN2-xLUmz*f3UyH4|wuS ztj4kY2&zLnW1lm9DP7mA^2H{4GXs*7RdtVCfx1FqWKZN&&+YNO9JX5%aFYNi)g9}2 zY3a)y;Sf^!P~AKkhho3d8sC)H_`f<%c>o`&ptnYTaqNy2**|z zt$VF+AqURt47)itVj&PNeTdgz>bu@$%@NXf7$p!x z0GzfCqT4sGdn)AVj_dC!1}+A_==EV~b$iM|vthgumo zO>-d&1+L^8o~GjAEC)itF^`i=l*=3%+^XG4s{AfAK`Z4 z>2H(n>5>Z6ilQ5=yS;esA@628r5e6j26GL?e*X!!*LJ$1Ho{fBS9hQ^`OIL!HAOw% z2xBfofR#7lwcy&&Y2bi)^dEF##(mEkqq~2P^FILBBMwBVc?}g<6__poPz*j~RKj15 z|C>~tA*-B;P|4rhIqLl~#R`u_``h5udw=rD)Z#qu$V#QfO-f8c>BnbjgZKUL5 z?_+%_beBIuc{+lQKb^TKFZy~gVeGf}o_rQ5jj6L~SsnWdBhZI<{BXHp@d1$6tkQ#=cs0*4(xhGCSD`!1GjU^e z{v5I?P366&l~vH7`{np_kK~NyP22^P>upE_f2wcsOhvk(v$La3Y!Xl8LzTUA=e}G` ze5L=MbB=imx+uodwKxTX9oa0YWc$KRb42PWbn-o1?(;~v8h)Xn(CfWeT>-g-ioNEN zO#n2S>dZBtIN8Dz$=hTBwR&~jvbCGTdp0J+TKtppb^V#P630nt&v`*V76%LIRBdK* z5OB|p%*H-3dS|&a-`gr( z>0-I>f0w!1137pG;k4B8%N`q zibc<=4{O#h+j5dh?7gAzVQvLK#TiKF@RzZ~K0dh8DG(42Pw1??%B>)4o(rX2mqMtPO2LbS5L zbeKJx_}26*%w(AYNw}Ifl(_ZZcV9|#PkXh>`pnrF$D20>;>Ffx;A_1zg9F(Tw=Mmg zJ0IJXWUv$zm?NC@U1ywy88sB#k3YnQSZB|AsfBdr)$F^n-Ww7#)tPh=7%d+n9h&VN z>LvNA^?{Od-8dygFfSVTXN0>}Z^U0Q3`KA5xhmJza&b+72aJ`EA!Yqt{IYAsl!Zbu zW#%+^)r{a1m>L1djrMr_Bum(xwt_b7^wVOlrw^Uv$0viAWr~6)J6n&=y(?h@6UKk{ zqKd;LrETJrtHwFCylPx$;i>2rYGq3_4H+5uJW~SeTYjtLdZ0nRVxfh^JpJWWAbwcLSb~OKnU$Z+bt3 zqz$xm>eBJ`%1OVSd-W4I`!Xl5d8wVufQQ4MY`&AI@-SbXRuYxBe(qfnI0n%slaC~> zQ|!xTN}TYtRkbxXjq!uWH!i(Zh45d&TR~HjSGZY#s%4wWPbqhb$>Yml0!w1_%;>R< zxnG970=t~O@DIgAiudoxnT z7tiwe$=Dnt^yP${8;L`oKJ>1}{gNqJh|zOBok4B#_+m-1bEc-)YGiG-vtCyL;;W9U zUm?PzavAl?B6<74v9Fd+c{PruEEWqMkyG600B3l@>;fI7 z$>{J(e~@c z8g~+TGOqV?R)=CjsO)ZNxVR~VCJ#mpt7-eP>8UaOQ#@P9h`0@$FrPyJEE$5oT2++> zbg&HilutihXNnQxYO_{|Qc9KGCU^D4t3HlAfoT&xJL6L+BCFlp$;emlWV#@+XE;6a zjzho`!o+XhELl^gzoyy9YKV0SEsy=wz*VA=TULJoo%R}r-7XlJu6IC4h=cHbW}Jb} zNqHIfeJrOH*$BYvA9$@kykxKq)*2tSa3~~zofJ}2I3yYWlVtcL85w^>AH4i7XUVLL z$+Gu!>9Ifuc#n$!^cgF4$8YA)1`iR}g?u&yfPKXw4}bkXQ_i{zD#7=mdrl}@cMWwh z`F~bbZz9;5aNg)ZH$v&_H3E=S6&wrxQ!}ML4XfcoHd?D-R|$af4lXqr=kO<0<%ZE> z%anKj)LM-{Yx1no3+9%u_?y-${YjN`YF^C0f&a3Be?Rg6PfR@(>Crc-O)_QDOO1o( zt=${lbXgvSDRC6Na?L>9^p9(u0|Lj1ej!TSX1?=;F!|e9@h|;i<-js>p?a-bDf+QX zM$Z$Nlyt83Sr>_>_cQ9B0bU+6C>zYi-pyma$*Hx7p58&;D7;2Qsl$YmbVhe%F%B_* z^~)6Mc8R#Z04T{{AbG%E|B;e7MksD$Ii)zz;*>$r{EsTV+C3e`5=73^R&!BWThv1Mu9&1&Bu*W}Lz!j|%09>+V%N;|->70b%PVWKYhRC>5gC*`ImVVA^P9xrV}oda4$Gz@*VIVx4APJ9f*7b8}0sDaf0qnt^7rJ{%9<0c-Z=iekB5B}vdp?{WDU28>7w$c1N z>9yEFQM9723AI@;R5!BwkL~;B*!+mNdI=7Xn7Fi>ruIA%#y_r4{UCu(i48`JSqsNK zD8$M@;g+m}6()T6WW`Y4))>8-g!hayC9hwE#=VPYZ(zQV;(I_(f%pn0z76eT#gJ01 zQ8hWV*owBJ6MO-g{J`vE*TQ_;5@omN`WyNek8g;ZF1dtz#z`kBGta_=&>HPKq}U&w zT<1rEcnYgaRgo@QX(qE4;E`G#{eWj(-5D7*AD|-nk&JGisIyL$0wmmE_EzF)J;S#b zc(!0#rCYZL4}r{ zf$oQz452#lz>nNMjEoB%yWbJ5`c3W_-L@m8XSH)i9YL2zTx$8S7aLTdZ=FfM+m&%u zupM(6d1{UfcqSAY(VFE&>LxpuOSHAJG)V@G;V036HPAB z33!y@(U{JXH1k8Gk{8Bg3_6*20DZ4EL{rA?(KDzb>3lmf(lRT|Tz2=4Gv#s{gC(BM zfQk~fx5C$IAK_WBtQb%ymrN5juyp;qpQTCF$j-ho_xNJ=h%!ZvGv7?SNV1=3V!}(a zv(FRcDykG2vFWg@*yLPC@HxecjuwK=!8F(~-I1m;`$70ng%9}yx2kU}Emj?CSp)#0 ze>LoLKhtWXHAbN0C^!ZJMh-H}W8JkZ>9HE!L&9m~1Pl;C;IqmhOEkY!WmK8`sXVP*mi71hjFk28V@23-ZDs=0}-I>lFMhhK09}1FG=6iLZG$oJl-|cc54b0=1(Xb)}8%vgua@mbH!e-NS2a0VcT(!FurJC2CH)Eo0?4)&L5>(j}Vdm8*HP zfEG?F#VR38$(XPivc$c#Q^No5GqzMDf`fti7H70}X4)2FtDqFRk@Wb@el>(Rm)y6v zedo;bSmtT%;Fd#>vJ z8WTRpbV|3!LNiUBGmCPw1A9RIu~P~*n2(UjZcC=6*2qqa%VRhWq%Mn}B}(p9d8SY9 zyGeG#8ofIvgO6u|x~gBlv?Cc-KFlQjFo>Yh#)hFJmQL8+X$QI9`V<=TyQTZXIcOwAq?iT+=sVb4ZWMJX-k4~ZJ4p>HF70b972?l`%~Vot zMe?E7rfU@zwoG-azrI@!6v*M~SC1l#6L3L^7pY!>-9MwtthLs|MN>T{dBVSAIl9;~ zo@()hvN6iG-srgO6w4g9TbJ?xED)pcQBk4^bBtA09~E6g?{s~wso3f-LU}PKuL~<8 z>=NiIIU27gl;hlOxosw?F#^b*XQGe?n6qk=WwlWkF?aWC8l2bV$xIS6#_vbS>MQ(c zpKh+s_ux&ue6p`}HCK%@U6ieTd}X!5%{FLzej~urQ4W?Lc(&n$H}7>_oMu^Gw2^qj z#ZtM&N)XvAU#V+$Fjb|@in!oiQ$=n9Fx62Sylz&zlDZMhN!*67gDDe$%1A>3FjDW_ zFVyT3{MuOQxB!gq+12>ti2GmpF)PvS4(%(Zcb;0pgWCrT+6^BO&9`D@sP8$SC*DS*5x4h>uNcjiH{V+y>$ZPV$E>zmADi9+f@RvM`=I+fER~g13gP& z0?^@v|Gcm#7rdfyo7huMO32z^JNF~b*4?b4;9V)s`1irZhpi_hV+7zMA6{c@>>t&n z!Lte82y!O?*L{@G)WM1SQp~%9IO&Q_;-o|M1>T^R9piAC${|ichR*BaNG+EGb<|+h1c0veSR#06g#e^%sS;1fN|P~fx8~3SDno8!Fo9wn zl#YSp8Ivw&4>y{nFy0po-MJEz=iHTvO>oo*t&UE2 VXm4x$aXA04w3Gj&E+xYB{{a04O0NI_ literal 0 HcmV?d00001 diff --git a/docs/images/prowler-app/multi-tenant/organizations-card.png b/docs/images/prowler-app/multi-tenant/organizations-card.png new file mode 100644 index 0000000000000000000000000000000000000000..10ddb4b15bf58cf17d9e6d98a6394986093b9def GIT binary patch literal 102728 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

  • =qe|Se4EuUl2t#hf19D_ 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 literal 0 HcmV?d00001 diff --git a/docs/images/prowler-app/multi-tenant/switch-organization-modal.png b/docs/images/prowler-app/multi-tenant/switch-organization-modal.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e2607a75b281ad51e31446c21363b55d343b20 GIT binary patch literal 14714 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 K>!XUD|Gxl7+B+Wr literal 0 HcmV?d00001 diff --git a/docs/user-guide/tutorials/prowler-app-multi-tenant.mdx b/docs/user-guide/tutorials/prowler-app-multi-tenant.mdx new file mode 100644 index 0000000000..69577c2f0c --- /dev/null +++ b/docs/user-guide/tutorials/prowler-app-multi-tenant.mdx @@ -0,0 +1,151 @@ +--- +title: 'Managing Organizations (Multi-Tenant)' +--- + +import { VersionBadge } from "/snippets/version-badge.mdx" + + + +Prowler App supports multi-tenancy through **Organizations**, allowing users to belong to multiple isolated environments within a single account. Each organization maintains its own providers, scans, findings, and user memberships, ensuring complete data separation between teams or business units. + +## Key Concepts + +* **Organization (Tenant):** An isolated workspace containing its own providers, scans, findings, roles, and users. Every Prowler account operates within at least one organization. +* **Membership:** The association between a user and an organization, including the membership role (`owner` or `member`). +* **Active Organization:** The organization currently in use for the session. All actions (scans, findings, provider management) apply to the active organization. + + +When a new account is created without an invitation, a default organization is automatically provisioned. Accounts created through an invitation join the inviter's organization instead. + + + +## Viewing Organizations + +To view all organizations associated with an account, navigate to the **Profile** page. The **Organizations** card displays every organization the user belongs to, including the role, name, join date, and whether it is the currently active organization. + +Organizations card in profile page + +## Creating an Organization + +To create a new organization: + +1. Navigate to the **Profile** page. + +2. In the **Organizations** card, click the **Create organization** button. + + Create organization button + +3. Enter a name for the new organization (maximum 100 characters). + + Create organization modal + +4. Click **Create**. The session automatically switches to the newly created organization. + + +Creating an organization requires being authenticated. Any user can create a new organization regardless of their current role. + + + +## Switching Between Organizations + +To switch the active organization: + +1. Navigate to the **Profile** page. + +2. In the **Organizations** card, locate the organization to switch to. + +3. Click the **Switch** button next to the desired organization. + +4. Confirm the switch in the dialog. The page reloads with the new organization's context, and all subsequent actions apply to it. + + Switch organization confirmation modal + + +The currently active organization is indicated by an **Active** badge. Switching updates the session tokens, so the page will reload automatically. + + + +## Editing an Organization Name + +Organization owners with the **Manage Account** permission can rename an organization: + +1. Navigate to the **Profile** page. + +2. In the **Organizations** card, click the **Edit** button next to the organization. + +3. Update the name and save the changes. + + Edit organization name modal + +## Deleting an Organization + +Organization owners with the **Manage Account** permission can delete an organization, provided they belong to at least two organizations (the last remaining organization cannot be deleted). + +### Deleting a Non-Active Organization + +1. Navigate to the **Profile** page. + +2. Click the **Delete** button next to the organization to remove. + +3. Type the organization name to confirm deletion. + + Delete organization confirmation modal + +4. Click **Delete**. The organization and all its associated data (providers, scans, findings) are permanently removed. + +### Deleting the Active Organization + +When deleting the currently active organization, an additional step is required: + +1. Navigate to the **Profile** page. + +2. Click the **Delete** button next to the active organization. + +3. Select which organization to switch to after deletion. + +4. Type the organization name to confirm. + + Delete active organization modal with target selection + +5. Click **Delete**. The session switches to the selected organization, and the deleted organization's data is permanently removed. + + +Deleting an organization is irreversible. All providers, scans, findings, and configuration data within the organization are permanently deleted. Users who belong only to the deleted organization will lose access to Prowler. + + +## Accepting an Invitation to an Organization + +When invited to join an organization, the invited user receives a link to accept the invitation. The flow adapts depending on whether the user already has a Prowler account: + +### Existing Users + +1. Open the invitation link. + +2. If already authenticated, the invitation is accepted automatically and the user is redirected to Prowler App. + +3. If not authenticated, choose **I have an account -- Sign in**, authenticate with existing credentials, and the invitation is accepted upon sign-in. + + Sign in screen after choosing I have an account from invitation + +### New Users + +1. Open the invitation link. + +2. Choose **I'm new -- Create an account**. + +3. Complete the sign-up process. Upon account creation, the invitation is accepted and the user joins the inviter's organization. + + +Invitations expire after 7 days. If an invitation has expired, contact the organization administrator to send a new one. For more details on invitation management, see [Managing Users and Role-Based Access Control (RBAC)](/user-guide/tutorials/prowler-app-rbac#invitations). + + + +## Permissions Reference + +| Action | Required Conditions | +|--------|-------------------| +| View organizations | Any authenticated user | +| Create an organization | Any authenticated user | +| Switch organizations | Any authenticated user | +| Edit organization name | Organization owner with **Manage Account** permission | +| Delete an organization | Organization owner with **Manage Account** permission; must belong to more than one organization | From e4b2950436a6b3e46018e1933ff1a9ddd408d2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pe=C3=B1a?= Date: Thu, 9 Apr 2026 18:07:43 +0200 Subject: [PATCH 36/36] refactor(api): split finding-groups status from muted state (#10630) --- api/CHANGELOG.md | 3 + api/src/backend/api/filters.py | 5 +- .../0088_finding_group_status_muted_fields.py | 95 ++++++ ...089_backfill_finding_group_status_muted.py | 31 ++ api/src/backend/api/models.py | 34 +- api/src/backend/api/tests/test_views.py | 316 +++++++++++++++++- api/src/backend/api/v1/serializers.py | 19 ++ api/src/backend/api/v1/views.py | 223 +++++++++--- api/src/backend/tasks/jobs/scan.py | 86 ++++- api/src/backend/tasks/tasks.py | 49 ++- api/src/backend/tasks/tests/test_tasks.py | 85 ++++- 11 files changed, 853 insertions(+), 93 deletions(-) create mode 100644 api/src/backend/api/migrations/0088_finding_group_status_muted_fields.py create mode 100644 api/src/backend/api/migrations/0089_backfill_finding_group_status_muted.py diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 33c573924a..0fbb745d3c 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -11,15 +11,18 @@ All notable changes to the **Prowler API** are documented in this file. - `VALKEY_SCHEME`, `VALKEY_USERNAME`, and `VALKEY_PASSWORD` environment variables to configure Celery broker TLS/auth connection details for Valkey/ElastiCache [(#10420)](https://github.com/prowler-cloud/prowler/pull/10420) - `Vercel` provider support [(#10190)](https://github.com/prowler-cloud/prowler/pull/10190) - Finding groups list and latest endpoints support `sort=delta`, ordering by `new_count` then `changed_count` so groups with the most new findings rank highest [(#10606)](https://github.com/prowler-cloud/prowler/pull/10606) +- Finding group resources endpoints (`/finding-groups/{check_id}/resources` and `/finding-groups/latest/{check_id}/resources`) now expose `finding_id` per row, pointing to the most recent matching Finding for each resource. UUIDv7 ordering guarantees `Max(finding__id)` resolves to the latest snapshot [(#10630)](https://github.com/prowler-cloud/prowler/pull/10630) - Handle CIS and CISA SCuBA compliance framework from google workspace [(#10629)](https://github.com/prowler-cloud/prowler/pull/10629) ### ๐Ÿ”„ Changed +- Finding groups list/latest/resources now expose `status` โˆˆ `{FAIL, PASS, MANUAL}` and `muted: bool` as orthogonal fields. The aggregated `status` reflects the underlying check outcome regardless of mute state, and `muted=true` signals that every finding in the group/resource is muted. New `manual_count` is exposed alongside `pass_count`/`fail_count`, plus `pass_muted_count`/`fail_muted_count`/`manual_muted_count` siblings so clients can isolate the muted half of each status. The `new_*`/`changed_*` deltas are now broken down by status and mute state via 12 new counters (`new_fail_count`, `new_fail_muted_count`, `new_pass_count`, `new_pass_muted_count`, `new_manual_count`, `new_manual_muted_count` and the matching `changed_*` set). New `filter[muted]=true|false` and `sort=status` (FAIL > PASS > MANUAL) / `sort=muted` are supported. `filter[status]=MUTED` is no longer accepted [(#10630)](https://github.com/prowler-cloud/prowler/pull/10630) - Attack Paths: Periodic cleanup of stale scans with dead-worker detection via Celery inspect, marking orphaned `EXECUTING` scans as `FAILED` and recovering `graph_data_ready` [(#10387)](https://github.com/prowler-cloud/prowler/pull/10387) - Attack Paths: Replace `_provider_id` property with `_Provider_{uuid}` label for provider isolation, add regex-based label injection for custom queries [(#10402)](https://github.com/prowler-cloud/prowler/pull/10402) ### ๐Ÿž Fixed +- `reaggregate_all_finding_group_summaries_task` now refreshes finding group daily summaries for every `(provider, day)` combination instead of only the latest scan per provider, matching the unbounded scope of `mute_historical_findings_task`. Mute rule operations no longer leave older daily summaries drifting from the underlying muted findings [(#10630)](https://github.com/prowler-cloud/prowler/pull/10630) - Finding groups list/latest now apply computed status/severity filters and finding-level prefilters (delta, region, service, category, resource group, scan, resource type), plus `check_title` support for sort/filter consistency [(#10428)](https://github.com/prowler-cloud/prowler/pull/10428) - Populate compliance data inside `check_metadata` for findings, which was always returned as `null` [(#10449)](https://github.com/prowler-cloud/prowler/pull/10449) - 403 error for admin users listing tenants due to roles query not using the admin database connection [(#10460)](https://github.com/prowler-cloud/prowler/pull/10460) diff --git a/api/src/backend/api/filters.py b/api/src/backend/api/filters.py index a496a0bf67..fa31289964 100644 --- a/api/src/backend/api/filters.py +++ b/api/src/backend/api/filters.py @@ -1115,13 +1115,14 @@ class FindingGroupAggregatedComputedFilter(FilterSet): STATUS_CHOICES = ( ("FAIL", "Fail"), ("PASS", "Pass"), - ("MUTED", "Muted"), + ("MANUAL", "Manual"), ) status = ChoiceFilter(method="filter_status", choices=STATUS_CHOICES) status__in = CharInFilter(method="filter_status_in", lookup_expr="in") severity = ChoiceFilter(method="filter_severity", choices=SeverityChoices) severity__in = CharInFilter(method="filter_severity_in", lookup_expr="in") + muted = BooleanFilter(field_name="muted") include_muted = BooleanFilter(method="filter_include_muted") def filter_status(self, queryset, name, value): @@ -1198,7 +1199,7 @@ class FindingGroupAggregatedComputedFilter(FilterSet): if value is True: return queryset # include_muted=false: exclude fully-muted groups - return queryset.exclude(fail_count=0, pass_count=0, muted_count__gt=0) + return queryset.exclude(muted=True) class ProviderSecretFilter(FilterSet): diff --git a/api/src/backend/api/migrations/0088_finding_group_status_muted_fields.py b/api/src/backend/api/migrations/0088_finding_group_status_muted_fields.py new file mode 100644 index 0000000000..ff3b981435 --- /dev/null +++ b/api/src/backend/api/migrations/0088_finding_group_status_muted_fields.py @@ -0,0 +1,95 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0087_vercel_provider"), + ] + + operations = [ + migrations.AddField( + model_name="findinggroupdailysummary", + name="manual_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="pass_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="fail_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="manual_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="muted", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_fail_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_fail_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_pass_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_pass_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_manual_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="new_manual_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_fail_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_fail_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_pass_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_pass_muted_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_manual_count", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="findinggroupdailysummary", + name="changed_manual_muted_count", + field=models.IntegerField(default=0), + ), + ] diff --git a/api/src/backend/api/migrations/0089_backfill_finding_group_status_muted.py b/api/src/backend/api/migrations/0089_backfill_finding_group_status_muted.py new file mode 100644 index 0000000000..501fcf3cb4 --- /dev/null +++ b/api/src/backend/api/migrations/0089_backfill_finding_group_status_muted.py @@ -0,0 +1,31 @@ +from django.db import migrations +from tasks.tasks import backfill_finding_group_summaries_task + +from api.db_router import MainRouter +from api.rls import Tenant + + +def trigger_backfill_task(apps, schema_editor): + """ + Re-dispatch the finding-group backfill task for every tenant so the new + `manual_count` and `muted` columns added in 0088 get populated from the + last 10 days of completed scans. + + The aggregator (`aggregate_finding_group_summaries`) recomputes every + column on each call, so it back-populates the new fields without touching + the existing ones beyond a normal upsert. + """ + tenant_ids = Tenant.objects.using(MainRouter.admin_db).values_list("id", flat=True) + + for tenant_id in tenant_ids: + backfill_finding_group_summaries_task.delay(tenant_id=str(tenant_id), days=10) + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0088_finding_group_status_muted_fields"), + ] + + operations = [ + migrations.RunPython(trigger_backfill_task, migrations.RunPython.noop), + ] diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index 5e0880be08..7f3131fe7b 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -1748,15 +1748,45 @@ class FindingGroupDailySummary(RowLevelSecurityProtectedModel): # Severity stored as integer for MAX aggregation (5=critical, 4=high, etc.) severity_order = models.SmallIntegerField(default=1) - # Finding counts + # Finding counts (inclusive of muted findings; use the `muted` flag to + # tell whether the group has any actionable findings). pass_count = models.IntegerField(default=0) fail_count = models.IntegerField(default=0) + manual_count = models.IntegerField(default=0) muted_count = models.IntegerField(default=0) - # Delta counts + # Status counts restricted to muted findings, so clients can isolate the + # muted half of each status (e.g. `pass_count - pass_muted_count` gives the + # actionable PASS findings). + pass_muted_count = models.IntegerField(default=0) + fail_muted_count = models.IntegerField(default=0) + manual_muted_count = models.IntegerField(default=0) + + # Whether every finding for this (provider, check, day) is muted. + muted = models.BooleanField(default=False) + + # Delta counts (non-muted, kept for convenience and as a "total" view). new_count = models.IntegerField(default=0) changed_count = models.IntegerField(default=0) + # Delta breakdown by (status, muted) so clients can answer questions like + # "how many new failing findings appeared in this scan?" without scanning + # the underlying findings table. Mirrors the existing pass/fail/manual + # naming, with `_muted_count` siblings tracking the muted half of each + # bucket explicitly. + new_fail_count = models.IntegerField(default=0) + new_fail_muted_count = models.IntegerField(default=0) + new_pass_count = models.IntegerField(default=0) + new_pass_muted_count = models.IntegerField(default=0) + new_manual_count = models.IntegerField(default=0) + new_manual_muted_count = models.IntegerField(default=0) + changed_fail_count = models.IntegerField(default=0) + changed_fail_muted_count = models.IntegerField(default=0) + changed_pass_count = models.IntegerField(default=0) + changed_pass_muted_count = models.IntegerField(default=0) + changed_manual_count = models.IntegerField(default=0) + changed_manual_muted_count = models.IntegerField(default=0) + # Resource counts resources_fail = models.IntegerField(default=0) resources_total = models.IntegerField(default=0) diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 439a355193..7457f20f4d 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -15445,10 +15445,16 @@ class TestFindingGroupViewSet: # iam_password_policy has only PASS findings assert data[0]["attributes"]["status"] == "PASS" - def test_finding_groups_status_muted_all( + def test_finding_groups_fully_muted_group_reflects_underlying_status( self, authenticated_client, finding_groups_fixture ): - """Test that MUTED status returned when all findings are muted.""" + """A fully-muted group still surfaces its underlying status (no MUTED). + + rds_encryption has 2 muted FAIL findings, so the group must report + status=FAIL (the orthogonal `muted` boolean signals it isn't actionable). + The statusร—muted breakdown lets clients answer 'how many failing + findings are muted in this group'. + """ response = authenticated_client.get( reverse("finding-group-list"), {"filter[inserted_at]": TODAY, "filter[check_id]": "rds_encryption"}, @@ -15456,8 +15462,21 @@ class TestFindingGroupViewSet: assert response.status_code == status.HTTP_200_OK data = response.json()["data"] assert len(data) == 1 - # rds_encryption has all muted findings - assert data[0]["attributes"]["status"] == "MUTED" + attrs = data[0]["attributes"] + assert attrs["status"] == "FAIL" + assert attrs["muted"] is True + assert attrs["fail_count"] == 2 + assert attrs["fail_muted_count"] == 2 + assert attrs["pass_muted_count"] == 0 + assert attrs["manual_muted_count"] == 0 + assert attrs["muted_count"] == 2 + # Sanity: the per-status muted counts must add up to muted_count. + assert ( + attrs["pass_muted_count"] + + attrs["fail_muted_count"] + + attrs["manual_muted_count"] + == attrs["muted_count"] + ) def test_finding_groups_status_filter( self, authenticated_client, finding_groups_fixture @@ -15949,7 +15968,7 @@ class TestFindingGroupViewSet: "extra_filters", [ {}, - {"filter[muted]": "include"}, + {"filter[delta]": "new"}, ], ids=["summary_path", "finding_level_path"], ) @@ -15967,7 +15986,8 @@ class TestFindingGroupViewSet: Parametrized to cover both aggregation paths: - summary_path: default, uses _CheckTitleToCheckIdMixin on summaries - - finding_level_path: filter[muted]=include forces CommonFindingFilters + - finding_level_path: filter[delta]=new forces _aggregate_findings via + CommonFindingFilters (delta is finding-level, not summary-level) """ params = { "filter[inserted_at]": TODAY, @@ -16885,3 +16905,287 @@ class TestFindingGroupViewSet: data = response.json()["data"] # Should still return data, not filtered by the old date assert len(data) == 5 + + def test_finding_groups_status_choices_no_muted( + self, authenticated_client, finding_groups_fixture + ): + """Every returned group must have status โˆˆ {FAIL, PASS, MANUAL}.""" + response = authenticated_client.get( + reverse("finding-group-list"), + {"filter[inserted_at]": TODAY}, + ) + assert response.status_code == status.HTTP_200_OK + statuses = {item["attributes"]["status"] for item in response.json()["data"]} + assert statuses, "fixture should produce at least one group" + assert statuses <= {"FAIL", "PASS", "MANUAL"} + assert "MUTED" not in statuses + + def test_finding_groups_serializer_exposes_muted_and_manual_count( + self, authenticated_client, finding_groups_fixture + ): + """The /finding-groups payload must expose `muted`, `manual_count` and + the per-status muted siblings (`pass_muted_count`/`fail_muted_count`/ + `manual_muted_count`).""" + response = authenticated_client.get( + reverse("finding-group-list"), + {"filter[inserted_at]": TODAY, "filter[check_id]": "iam_password_policy"}, + ) + assert response.status_code == status.HTTP_200_OK + attrs = response.json()["data"][0]["attributes"] + assert "muted" in attrs and isinstance(attrs["muted"], bool) + assert "manual_count" in attrs and isinstance(attrs["manual_count"], int) + assert attrs["muted"] is False # iam_password_policy has only non-muted PASS + assert attrs["manual_count"] == 0 + assert attrs["pass_muted_count"] == 0 + assert attrs["fail_muted_count"] == 0 + assert attrs["manual_muted_count"] == 0 + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_filter_status_muted_is_rejected( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """`filter[status]=MUTED` is no longer a valid status value.""" + params = {"filter[status]": "MUTED"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_400_BAD_REQUEST + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_filter_muted_true( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """`filter[muted]=true` returns only fully-muted groups.""" + params = {"filter[muted]": "true"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + check_ids = {item["id"] for item in data} + # Only rds_encryption is fully muted in the fixture + assert check_ids == {"rds_encryption"} + assert all(item["attributes"]["muted"] is True for item in data) + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_filter_muted_false( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """`filter[muted]=false` returns only groups with actionable findings.""" + params = {"filter[muted]": "false"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + check_ids = {item["id"] for item in data} + assert "rds_encryption" not in check_ids + assert check_ids == { + "s3_bucket_public_access", + "ec2_instance_public_ip", + "iam_password_policy", + "cloudtrail_enabled", + } + assert all(item["attributes"]["muted"] is False for item in data) + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_sort_by_status( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """sort=status orders by aggregated status (FAIL > PASS > MANUAL).""" + priority = {"FAIL": 3, "PASS": 2, "MANUAL": 1} + params = {"sort": "-status"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert data, "fixture should produce groups" + + desc_keys = [priority[item["attributes"]["status"]] for item in data] + assert desc_keys == sorted(desc_keys, reverse=True) + + params["sort"] = "status" + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + asc_keys = [ + priority[item["attributes"]["status"]] for item in response.json()["data"] + ] + assert asc_keys == sorted(asc_keys) + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_sort_by_muted( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """sort=muted orders by the boolean muted attribute.""" + # Need include_muted=true so the fully-muted group is part of the result + params = {"sort": "-muted", "filter[include_muted]": "true"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert data, "fixture should produce groups" + + muted_values = [item["attributes"]["muted"] for item in data] + # Descending boolean: True (1) before False (0) + assert muted_values == sorted(muted_values, reverse=True) + + @pytest.mark.parametrize( + "endpoint_name", ["finding-group-list", "finding-group-latest"] + ) + def test_finding_groups_delta_status_breakdown( + self, authenticated_client, finding_groups_fixture, endpoint_name + ): + """`new_*` and `changed_*` counters split by status and mute state. + + s3_bucket_public_access has 1 new FAIL and 1 changed FAIL (both + non-muted) so the breakdown must reflect exactly that and the totals + must equal the sum of the buckets. + """ + params = {"filter[check_id]": "s3_bucket_public_access"} + if endpoint_name == "finding-group-list": + params["filter[inserted_at]"] = TODAY + + response = authenticated_client.get(reverse(endpoint_name), params) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert len(data) == 1 + attrs = data[0]["attributes"] + + assert attrs["new_fail_count"] == 1 + assert attrs["new_fail_muted_count"] == 0 + assert attrs["new_pass_count"] == 0 + assert attrs["new_pass_muted_count"] == 0 + assert attrs["new_manual_count"] == 0 + assert attrs["new_manual_muted_count"] == 0 + assert attrs["changed_fail_count"] == 1 + assert attrs["changed_fail_muted_count"] == 0 + assert attrs["changed_pass_count"] == 0 + assert attrs["changed_pass_muted_count"] == 0 + assert attrs["changed_manual_count"] == 0 + assert attrs["changed_manual_muted_count"] == 0 + + new_total = ( + attrs["new_fail_count"] + + attrs["new_fail_muted_count"] + + attrs["new_pass_count"] + + attrs["new_pass_muted_count"] + + attrs["new_manual_count"] + + attrs["new_manual_muted_count"] + ) + changed_total = ( + attrs["changed_fail_count"] + + attrs["changed_fail_muted_count"] + + attrs["changed_pass_count"] + + attrs["changed_pass_muted_count"] + + attrs["changed_manual_count"] + + attrs["changed_manual_muted_count"] + ) + # The non-muted variants of the breakdown must sum to the legacy + # totals (new_count/changed_count are stored as non-muted). + assert ( + attrs["new_fail_count"] + + attrs["new_pass_count"] + + attrs["new_manual_count"] + == attrs["new_count"] + ) + assert ( + attrs["changed_fail_count"] + + attrs["changed_pass_count"] + + attrs["changed_manual_count"] + == attrs["changed_count"] + ) + # And the *full* breakdown (including the muted halves) is exposed + # so clients can also count muted-only deltas without losing data. + assert new_total >= attrs["new_count"] + assert changed_total >= attrs["changed_count"] + + def test_finding_groups_resources_serializer_exposes_muted( + self, authenticated_client, finding_groups_fixture + ): + """The /finding-groups//resources payload must expose `muted`.""" + response = authenticated_client.get( + reverse( + "finding-group-resources", + kwargs={"pk": "rds_encryption"}, + ), + {"filter[inserted_at]": TODAY}, + ) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert data, "rds_encryption should expose its resources" + for item in data: + attrs = item["attributes"] + assert "muted" in attrs and isinstance(attrs["muted"], bool) + # rds_encryption has all muted findings + assert attrs["muted"] is True + # Status reflects the underlying check outcome (FAIL), not MUTED + assert attrs["status"] == "FAIL" + + def test_finding_groups_resources_exposes_finding_id( + self, authenticated_client, finding_groups_fixture + ): + """The /resources payload exposes the most recent matching finding_id. + + rds_encryption has 2 findings, one per resource. Each resource row must + report the UUID of its corresponding Finding (UUIDv7 ordering means + Max(finding__id) resolves to the latest snapshot in time). + """ + response = authenticated_client.get( + reverse( + "finding-group-resources", + kwargs={"pk": "rds_encryption"}, + ), + {"filter[inserted_at]": TODAY}, + ) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert data, "rds_encryption should expose its resources" + + rds_finding_ids = { + str(f.id) for f in finding_groups_fixture if f.check_id == "rds_encryption" + } + assert rds_finding_ids, "fixture sanity" + + for item in data: + attrs = item["attributes"] + assert "finding_id" in attrs + assert attrs["finding_id"] in rds_finding_ids + + def test_finding_groups_latest_resources_exposes_finding_id( + self, authenticated_client, finding_groups_fixture + ): + """The /latest/.../resources payload also exposes finding_id.""" + response = authenticated_client.get( + reverse( + "finding-group-latest_resources", + kwargs={"check_id": "rds_encryption"}, + ), + ) + assert response.status_code == status.HTTP_200_OK + data = response.json()["data"] + assert data, "rds_encryption should expose its resources via /latest" + + rds_finding_ids = { + str(f.id) for f in finding_groups_fixture if f.check_id == "rds_encryption" + } + for item in data: + attrs = item["attributes"] + assert "finding_id" in attrs + assert attrs["finding_id"] in rds_finding_ids diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 6af4d01000..52ec47f4f5 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -4185,6 +4185,7 @@ class FindingGroupSerializer(BaseSerializerV1): check_description = serializers.CharField(required=False, allow_null=True) severity = serializers.CharField() status = serializers.CharField() + muted = serializers.BooleanField() impacted_providers = serializers.ListField( child=serializers.CharField(), required=False ) @@ -4192,9 +4193,25 @@ class FindingGroupSerializer(BaseSerializerV1): resources_total = serializers.IntegerField() pass_count = serializers.IntegerField() fail_count = serializers.IntegerField() + manual_count = serializers.IntegerField() + pass_muted_count = serializers.IntegerField() + fail_muted_count = serializers.IntegerField() + manual_muted_count = serializers.IntegerField() muted_count = serializers.IntegerField() new_count = serializers.IntegerField() changed_count = serializers.IntegerField() + new_fail_count = serializers.IntegerField() + new_fail_muted_count = serializers.IntegerField() + new_pass_count = serializers.IntegerField() + new_pass_muted_count = serializers.IntegerField() + new_manual_count = serializers.IntegerField() + new_manual_muted_count = serializers.IntegerField() + changed_fail_count = serializers.IntegerField() + changed_fail_muted_count = serializers.IntegerField() + changed_pass_count = serializers.IntegerField() + changed_pass_muted_count = serializers.IntegerField() + changed_manual_count = serializers.IntegerField() + changed_manual_muted_count = serializers.IntegerField() first_seen_at = serializers.DateTimeField(required=False, allow_null=True) last_seen_at = serializers.DateTimeField(required=False, allow_null=True) failing_since = serializers.DateTimeField(required=False, allow_null=True) @@ -4214,8 +4231,10 @@ class FindingGroupResourceSerializer(BaseSerializerV1): id = serializers.UUIDField(source="resource_id") resource = serializers.SerializerMethodField() provider = serializers.SerializerMethodField() + finding_id = serializers.UUIDField() status = serializers.CharField() severity = serializers.CharField() + muted = serializers.BooleanField() delta = serializers.CharField(required=False, allow_null=True) first_seen_at = serializers.DateTimeField(required=False, allow_null=True) last_seen_at = serializers.DateTimeField(required=False, allow_null=True) diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index 2392b818ac..23cfe17f2d 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -26,10 +26,11 @@ from config.settings.social_login import ( ) from dj_rest_auth.registration.views import SocialLoginView from django.conf import settings as django_settings -from django.contrib.postgres.aggregates import ArrayAgg, StringAgg +from django.contrib.postgres.aggregates import ArrayAgg, BoolAnd, StringAgg from django.contrib.postgres.search import SearchQuery from django.db import transaction from django.db.models import ( + BooleanField, Case, CharField, Count, @@ -7076,9 +7077,29 @@ class FindingGroupViewSet(BaseRLSViewSet): severity_order=Max("severity_order"), pass_count=Sum("pass_count"), fail_count=Sum("fail_count"), + manual_count=Sum("manual_count"), + pass_muted_count=Sum("pass_muted_count"), + fail_muted_count=Sum("fail_muted_count"), + manual_muted_count=Sum("manual_muted_count"), muted_count=Sum("muted_count"), + # The group is muted only if every contributing daily summary is + # itself fully muted. BoolAnd returns False as soon as one row has + # at least one actionable finding. + muted=BoolAnd("muted"), new_count=Sum("new_count"), changed_count=Sum("changed_count"), + new_fail_count=Sum("new_fail_count"), + new_fail_muted_count=Sum("new_fail_muted_count"), + new_pass_count=Sum("new_pass_count"), + new_pass_muted_count=Sum("new_pass_muted_count"), + new_manual_count=Sum("new_manual_count"), + new_manual_muted_count=Sum("new_manual_muted_count"), + changed_fail_count=Sum("changed_fail_count"), + changed_fail_muted_count=Sum("changed_fail_muted_count"), + changed_pass_count=Sum("changed_pass_count"), + changed_pass_muted_count=Sum("changed_pass_muted_count"), + changed_manual_count=Sum("changed_manual_count"), + changed_manual_muted_count=Sum("changed_manual_muted_count"), resources_total=Sum("resources_total"), resources_fail=Sum("resources_fail"), impacted_providers_str=StringAgg( @@ -7104,39 +7125,95 @@ class FindingGroupViewSet(BaseRLSViewSet): output_field=IntegerField(), ) - return queryset.values("check_id").annotate( - severity_order=Max(severity_case), - pass_count=Count("id", filter=Q(status="PASS", muted=False)), - fail_count=Count("id", filter=Q(status="FAIL", muted=False)), - muted_count=Count("id", filter=Q(muted=True)), - new_count=Count("id", filter=Q(delta="new", muted=False)), - changed_count=Count("id", filter=Q(delta="changed", muted=False)), - resources_total=Count("resources__id", distinct=True), - resources_fail=Count( - "resources__id", - distinct=True, - filter=Q(status="FAIL", muted=False), - ), - impacted_providers_str=StringAgg( - Cast("scan__provider__provider", CharField()), - delimiter=",", - distinct=True, - default="", - ), - agg_first_seen_at=Min("first_seen_at"), - agg_last_seen_at=Max("inserted_at"), - agg_failing_since=Min( - "first_seen_at", filter=Q(status="FAIL", muted=False) - ), - check_title=Coalesce( - Max(KeyTextTransform("checktitle", "check_metadata")), - Max(KeyTextTransform("CheckTitle", "check_metadata")), - Max(KeyTextTransform("Checktitle", "check_metadata")), - ), - check_description=Coalesce( - Max(KeyTextTransform("description", "check_metadata")), - Max(KeyTextTransform("Description", "check_metadata")), - ), + # `pass_count`, `fail_count` and `manual_count` count *every* finding + # for the check (muted or not) so the aggregated `status` reflects the + # underlying check outcome regardless of mute state. Whether the group + # is actionable is signalled by the orthogonal `muted` flag below. + return ( + queryset.values("check_id") + .annotate( + severity_order=Max(severity_case), + pass_count=Count("id", filter=Q(status="PASS")), + fail_count=Count("id", filter=Q(status="FAIL")), + manual_count=Count("id", filter=Q(status="MANUAL")), + pass_muted_count=Count("id", filter=Q(status="PASS", muted=True)), + fail_muted_count=Count("id", filter=Q(status="FAIL", muted=True)), + manual_muted_count=Count("id", filter=Q(status="MANUAL", muted=True)), + muted_count=Count("id", filter=Q(muted=True)), + nonmuted_count=Count("id", filter=Q(muted=False)), + new_count=Count("id", filter=Q(delta="new", muted=False)), + changed_count=Count("id", filter=Q(delta="changed", muted=False)), + new_fail_count=Count( + "id", filter=Q(delta="new", status="FAIL", muted=False) + ), + new_fail_muted_count=Count( + "id", filter=Q(delta="new", status="FAIL", muted=True) + ), + new_pass_count=Count( + "id", filter=Q(delta="new", status="PASS", muted=False) + ), + new_pass_muted_count=Count( + "id", filter=Q(delta="new", status="PASS", muted=True) + ), + new_manual_count=Count( + "id", filter=Q(delta="new", status="MANUAL", muted=False) + ), + new_manual_muted_count=Count( + "id", filter=Q(delta="new", status="MANUAL", muted=True) + ), + changed_fail_count=Count( + "id", filter=Q(delta="changed", status="FAIL", muted=False) + ), + changed_fail_muted_count=Count( + "id", filter=Q(delta="changed", status="FAIL", muted=True) + ), + changed_pass_count=Count( + "id", filter=Q(delta="changed", status="PASS", muted=False) + ), + changed_pass_muted_count=Count( + "id", filter=Q(delta="changed", status="PASS", muted=True) + ), + changed_manual_count=Count( + "id", filter=Q(delta="changed", status="MANUAL", muted=False) + ), + changed_manual_muted_count=Count( + "id", filter=Q(delta="changed", status="MANUAL", muted=True) + ), + resources_total=Count("resources__id", distinct=True), + resources_fail=Count( + "resources__id", + distinct=True, + filter=Q(status="FAIL", muted=False), + ), + impacted_providers_str=StringAgg( + Cast("scan__provider__provider", CharField()), + delimiter=",", + distinct=True, + default="", + ), + agg_first_seen_at=Min("first_seen_at"), + agg_last_seen_at=Max("inserted_at"), + agg_failing_since=Min( + "first_seen_at", filter=Q(status="FAIL", muted=False) + ), + check_title=Coalesce( + Max(KeyTextTransform("checktitle", "check_metadata")), + Max(KeyTextTransform("CheckTitle", "check_metadata")), + Max(KeyTextTransform("Checktitle", "check_metadata")), + ), + check_description=Coalesce( + Max(KeyTextTransform("description", "check_metadata")), + Max(KeyTextTransform("Description", "check_metadata")), + ), + ) + .annotate( + # Group is muted only if it has zero non-muted findings. + muted=Case( + When(nonmuted_count=0, then=Value(True)), + default=Value(False), + output_field=BooleanField(), + ), + ) ) def _split_computed_aggregate_filters( @@ -7148,6 +7225,7 @@ class FindingGroupViewSet(BaseRLSViewSet): "status__in", "severity", "severity__in", + "muted", "include_muted", } finding_params = QueryDict(mutable=True) @@ -7179,7 +7257,8 @@ class FindingGroupViewSet(BaseRLSViewSet): Post-process aggregation results to add computed fields. - Converts severity integer back to string - - Computes aggregated status (FAIL > PASS > MUTED) + - Computes aggregated status (FAIL > PASS > MANUAL); the orthogonal + ``muted`` boolean is already on the row from the SQL aggregation - Converts provider string to list """ results = [] @@ -7197,13 +7276,19 @@ class FindingGroupViewSet(BaseRLSViewSet): if "agg_failing_since" in row: row["failing_since"] = row.pop("agg_failing_since") - # Compute aggregated status + # Drop the helper count we use to derive `muted` in the + # finding-level aggregation path. + row.pop("nonmuted_count", None) + + # Compute aggregated status. Counts are inclusive of muted findings, + # so the underlying check outcome surfaces even when the group is + # fully muted. if row.get("fail_count", 0) > 0: row["status"] = "FAIL" elif row.get("pass_count", 0) > 0: row["status"] = "PASS" else: - row["status"] = "MUTED" + row["status"] = "MANUAL" # Convert provider string to list providers_str = row.pop("impacted_providers_str", "") or "" @@ -7219,9 +7304,12 @@ class FindingGroupViewSet(BaseRLSViewSet): "check_id": "check_id", "check_title": "check_title", "severity": "severity_order", + "status": "status_order", + "muted": "muted", "delta": "delta_order", "fail_count": "fail_count", "pass_count": "pass_count", + "manual_count": "manual_count", "muted_count": "muted_count", "new_count": "new_count", "changed_count": "changed_count", @@ -7276,7 +7364,7 @@ class FindingGroupViewSet(BaseRLSViewSet): return ordering def _apply_aggregated_computed_filters(self, queryset, computed_params: QueryDict): - """Apply computed filters (status/severity) on aggregated finding-group rows.""" + """Apply computed filters (status/severity/muted) on aggregated finding-group rows.""" if not computed_params: return queryset @@ -7285,14 +7373,16 @@ class FindingGroupViewSet(BaseRLSViewSet): aggregated_status=Case( When(fail_count__gt=0, then=Value("FAIL")), When(pass_count__gt=0, then=Value("PASS")), - default=Value("MUTED"), + default=Value("MANUAL"), output_field=CharField(), ) ) - # Exclude fully-muted groups by default unless include_muted is set - if "include_muted" not in computed_params: - queryset = queryset.exclude(fail_count=0, pass_count=0, muted_count__gt=0) + # Exclude fully-muted groups by default unless the caller has opted in + # via either `include_muted` or an explicit `muted` filter (the latter + # gives the caller direct control over the column). + if "include_muted" not in computed_params and "muted" not in computed_params: + queryset = queryset.exclude(muted=True) filterset = FindingGroupAggregatedComputedFilter( computed_params, queryset=queryset @@ -7347,18 +7437,14 @@ class FindingGroupViewSet(BaseRLSViewSet): provider_type=Max("resource__provider__provider"), provider_uid=Max("resource__provider__uid"), provider_alias=Max("resource__provider__alias"), + # status_order considers ALL findings (muted or not) so it + # surfaces FAIL/PASS/MANUAL based on the underlying check + # outcome. Whether the resource is actionable is signalled by + # the orthogonal `muted` flag below. status_order=Max( Case( - When( - finding__status="FAIL", - finding__muted=False, - then=Value(3), - ), - When( - finding__status="PASS", - finding__muted=False, - then=Value(2), - ), + When(finding__status="FAIL", then=Value(3)), + When(finding__status="PASS", then=Value(2)), default=Value(1), output_field=IntegerField(), ) @@ -7390,6 +7476,8 @@ class FindingGroupViewSet(BaseRLSViewSet): ), first_seen_at=Min("finding__first_seen_at"), last_seen_at=Max("finding__inserted_at"), + # True only if every finding for this resource+check is muted. + muted=BoolAnd("finding__muted"), # Max() on muted_reason / check_metadata is safe because # all findings for the same resource+check share identical # values (mute rules and metadata are applied per-check). @@ -7397,6 +7485,12 @@ class FindingGroupViewSet(BaseRLSViewSet): resource_group=Max( KeyTextTransform("resourcegroup", "finding__check_metadata") ), + # Most recent matching Finding for this (resource, check): + # Finding.id is a UUIDv7 (time-ordered in its high 48 bits). + # Cast to text first because PostgreSQL has no built-in + # `max(uuid)` aggregate; on the canonical lowercase form a + # lexicographic Max() still resolves to the latest snapshot. + finding_id=Max(Cast("finding__id", output_field=CharField())), ) .filter(resource_id__isnull=False) ) @@ -7405,8 +7499,8 @@ class FindingGroupViewSet(BaseRLSViewSet): _RESOURCE_SORT_ANNOTATIONS = { "status_order": lambda: Max( Case( - When(finding__status="FAIL", finding__muted=False, then=Value(3)), - When(finding__status="PASS", finding__muted=False, then=Value(2)), + When(finding__status="FAIL", then=Value(3)), + When(finding__status="PASS", then=Value(2)), default=Value(1), output_field=IntegerField(), ) @@ -7480,7 +7574,7 @@ class FindingGroupViewSet(BaseRLSViewSet): elif status_order == 2: status = "PASS" else: - status = "MUTED" + status = "MANUAL" delta_order = row.get("delta_order", 0) if delta_order == 2: @@ -7508,8 +7602,12 @@ class FindingGroupViewSet(BaseRLSViewSet): "delta": delta, "first_seen_at": row["first_seen_at"], "last_seen_at": row["last_seen_at"], + "muted": bool(row.get("muted", False)), "muted_reason": row.get("muted_reason"), "resource_group": row.get("resource_group", ""), + "finding_id": ( + str(row["finding_id"]) if row.get("finding_id") else None + ), } ) @@ -7570,6 +7668,21 @@ class FindingGroupViewSet(BaseRLSViewSet): sort_param, self._FINDING_GROUP_SORT_MAP ) if ordering: + # status_order is annotated on demand so groups can be sorted by + # their aggregated status (FAIL > PASS > MANUAL), mirroring the + # priority used in _post_process_aggregation. Counts are + # inclusive of muted findings, so the underlying check outcome + # surfaces even for fully muted groups. + if any(field.lstrip("-") == "status_order" for field in ordering): + aggregated_queryset = aggregated_queryset.annotate( + status_order=Case( + When(fail_count__gt=0, then=Value(3)), + When(pass_count__gt=0, then=Value(2)), + default=Value(1), + output_field=IntegerField(), + ) + ) + # delta_order is a virtual sort field: expand it to a # lexicographic ordering by (new_count, changed_count) so groups # with more new findings rank higher, with changed_count as the diff --git a/api/src/backend/tasks/jobs/scan.py b/api/src/backend/tasks/jobs/scan.py index 364b12d146..2c73c97f2f 100644 --- a/api/src/backend/tasks/jobs/scan.py +++ b/api/src/backend/tasks/jobs/scan.py @@ -1803,7 +1803,12 @@ def aggregate_finding_group_summaries(tenant_id: str, scan_id: str): output_field=IntegerField(), ) - # Aggregate findings by check_id for this scan + # Aggregate findings by check_id for this scan. + # `pass_count`, `fail_count` and `manual_count` count *every* finding + # in this group, regardless of mute state, so the aggregated `status` + # always reflects the underlying check outcome (FAIL > PASS > MANUAL) + # even when the group is fully muted. The orthogonal `muted` flag is + # what tells whether the group has any actionable (non-muted) findings. aggregated = ( Finding.objects.filter( tenant_id=tenant_id, @@ -1812,11 +1817,52 @@ def aggregate_finding_group_summaries(tenant_id: str, scan_id: str): .values("check_id") .annotate( severity_order=Max(severity_case), - pass_count=Count("id", filter=Q(status="PASS", muted=False)), - fail_count=Count("id", filter=Q(status="FAIL", muted=False)), + pass_count=Count("id", filter=Q(status="PASS")), + fail_count=Count("id", filter=Q(status="FAIL")), + manual_count=Count("id", filter=Q(status="MANUAL")), + pass_muted_count=Count("id", filter=Q(status="PASS", muted=True)), + fail_muted_count=Count("id", filter=Q(status="FAIL", muted=True)), + manual_muted_count=Count("id", filter=Q(status="MANUAL", muted=True)), muted_count=Count("id", filter=Q(muted=True)), + nonmuted_count=Count("id", filter=Q(muted=False)), new_count=Count("id", filter=Q(delta="new", muted=False)), changed_count=Count("id", filter=Q(delta="changed", muted=False)), + new_fail_count=Count( + "id", filter=Q(delta="new", status="FAIL", muted=False) + ), + new_fail_muted_count=Count( + "id", filter=Q(delta="new", status="FAIL", muted=True) + ), + new_pass_count=Count( + "id", filter=Q(delta="new", status="PASS", muted=False) + ), + new_pass_muted_count=Count( + "id", filter=Q(delta="new", status="PASS", muted=True) + ), + new_manual_count=Count( + "id", filter=Q(delta="new", status="MANUAL", muted=False) + ), + new_manual_muted_count=Count( + "id", filter=Q(delta="new", status="MANUAL", muted=True) + ), + changed_fail_count=Count( + "id", filter=Q(delta="changed", status="FAIL", muted=False) + ), + changed_fail_muted_count=Count( + "id", filter=Q(delta="changed", status="FAIL", muted=True) + ), + changed_pass_count=Count( + "id", filter=Q(delta="changed", status="PASS", muted=False) + ), + changed_pass_muted_count=Count( + "id", filter=Q(delta="changed", status="PASS", muted=True) + ), + changed_manual_count=Count( + "id", filter=Q(delta="changed", status="MANUAL", muted=False) + ), + changed_manual_muted_count=Count( + "id", filter=Q(delta="changed", status="MANUAL", muted=True) + ), resources_total=Count("resources__id", distinct=True), resources_fail=Count( "resources__id", @@ -1895,9 +1941,26 @@ def aggregate_finding_group_summaries(tenant_id: str, scan_id: str): severity_order=row["severity_order"] or 1, pass_count=row["pass_count"], fail_count=row["fail_count"], + manual_count=row["manual_count"], + pass_muted_count=row["pass_muted_count"], + fail_muted_count=row["fail_muted_count"], + manual_muted_count=row["manual_muted_count"], muted_count=row["muted_count"], + muted=row["nonmuted_count"] == 0, new_count=row["new_count"], changed_count=row["changed_count"], + new_fail_count=row["new_fail_count"], + new_fail_muted_count=row["new_fail_muted_count"], + new_pass_count=row["new_pass_count"], + new_pass_muted_count=row["new_pass_muted_count"], + new_manual_count=row["new_manual_count"], + new_manual_muted_count=row["new_manual_muted_count"], + changed_fail_count=row["changed_fail_count"], + changed_fail_muted_count=row["changed_fail_muted_count"], + changed_pass_count=row["changed_pass_count"], + changed_pass_muted_count=row["changed_pass_muted_count"], + changed_manual_count=row["changed_manual_count"], + changed_manual_muted_count=row["changed_manual_muted_count"], resources_total=row["resources_total"], resources_fail=row["resources_fail"], first_seen_at=row["agg_first_seen_at"], @@ -1917,9 +1980,26 @@ def aggregate_finding_group_summaries(tenant_id: str, scan_id: str): "severity_order", "pass_count", "fail_count", + "manual_count", + "pass_muted_count", + "fail_muted_count", + "manual_muted_count", "muted_count", + "muted", "new_count", "changed_count", + "new_fail_count", + "new_fail_muted_count", + "new_pass_count", + "new_pass_muted_count", + "new_manual_count", + "new_manual_muted_count", + "changed_fail_count", + "changed_fail_muted_count", + "changed_pass_count", + "changed_pass_muted_count", + "changed_manual_count", + "changed_manual_muted_count", "resources_total", "resources_fail", "first_seen_at", diff --git a/api/src/backend/tasks/tasks.py b/api/src/backend/tasks/tasks.py index fbd0440af8..bbf4d89772 100644 --- a/api/src/backend/tasks/tasks.py +++ b/api/src/backend/tasks/tasks.py @@ -771,26 +771,49 @@ def aggregate_finding_group_summaries_task(tenant_id: str, scan_id: str): ) @set_tenant(keep_tenant=True) def reaggregate_all_finding_group_summaries_task(tenant_id: str): - """Reaggregate finding group summaries for all providers' latest completed scans.""" - latest_scan_ids = list( - Scan.objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED) - .order_by("provider_id", "-completed_at", "-inserted_at") - .distinct("provider_id") - .values_list("id", flat=True) + """Reaggregate finding group summaries for every (provider, day) combination. + + Mirrors the unbounded scope of `mute_historical_findings_task`: that task + rewrites every Finding row whose UID matches a mute rule, with no time + limit. To keep the daily summaries consistent with that update, this task + re-runs the aggregator on the latest completed scan of every (provider, + day) pair that exists in the database. Tasks are dispatched in parallel + via a Celery group so the wallclock scales with the worker pool, not with + the number of pairs. + """ + completed_scans = list( + Scan.objects.filter( + tenant_id=tenant_id, + state=StateChoices.COMPLETED, + completed_at__isnull=False, + ) + .order_by("-completed_at") + .values("id", "completed_at", "provider_id") ) - if latest_scan_ids: + + # Keep the latest scan per (provider, day) pair so the daily summary row + # the aggregator writes is the most recent snapshot of that day for that + # provider. Iterating from most recent to oldest means the first scan we + # see for a given key wins. + latest_scans: dict[tuple, str] = {} + for scan in completed_scans: + key = (scan["provider_id"], scan["completed_at"].date()) + if key not in latest_scans: + latest_scans[key] = str(scan["id"]) + + scan_ids = list(latest_scans.values()) + if scan_ids: logger.info( - "Reaggregating finding group summaries for %d scans: %s", - len(latest_scan_ids), - latest_scan_ids, + "Reaggregating finding group summaries for %d scans (provider x day)", + len(scan_ids), ) group( aggregate_finding_group_summaries_task.si( - tenant_id=tenant_id, scan_id=str(scan_id) + tenant_id=tenant_id, scan_id=scan_id ) - for scan_id in latest_scan_ids + for scan_id in scan_ids ).apply_async() - return {"scans_reaggregated": len(latest_scan_ids)} + return {"scans_reaggregated": len(scan_ids)} @shared_task(base=RLSTask, name="lighthouse-connection-check") diff --git a/api/src/backend/tasks/tests/test_tasks.py b/api/src/backend/tasks/tests/test_tasks.py index 8469b7db09..4a4108607e 100644 --- a/api/src/backend/tasks/tests/test_tasks.py +++ b/api/src/backend/tasks/tests/test_tasks.py @@ -1,6 +1,6 @@ import uuid from contextlib import contextmanager -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from unittest.mock import MagicMock, patch import openai @@ -2362,35 +2362,96 @@ class TestReaggregateAllFindingGroupSummaries: @patch("tasks.tasks.group") @patch("tasks.tasks.aggregate_finding_group_summaries_task") @patch("tasks.tasks.Scan.objects.filter") - def test_dispatches_subtasks_for_each_provider( + def test_dispatches_subtasks_for_each_provider_per_day( self, mock_scan_filter, mock_agg_task, mock_group ): - scan_id_1 = uuid.uuid4() - scan_id_2 = uuid.uuid4() + provider_id_1 = uuid.uuid4() + provider_id_2 = uuid.uuid4() + scan_id_today_p1 = uuid.uuid4() + scan_id_yesterday_p1 = uuid.uuid4() + scan_id_today_p2 = uuid.uuid4() + today = datetime.now(tz=timezone.utc) + yesterday = today - timedelta(days=1) + mock_group_result = MagicMock() mock_group.side_effect = lambda gen: (list(gen), mock_group_result)[1] - mock_scan_filter.return_value.order_by.return_value.distinct.return_value.values_list.return_value = [ - scan_id_1, - scan_id_2, + mock_scan_filter.return_value.order_by.return_value.values.return_value = [ + { + "id": scan_id_today_p1, + "completed_at": today, + "provider_id": provider_id_1, + }, + { + "id": scan_id_today_p2, + "completed_at": today, + "provider_id": provider_id_2, + }, + { + "id": scan_id_yesterday_p1, + "completed_at": yesterday, + "provider_id": provider_id_1, + }, ] result = reaggregate_all_finding_group_summaries_task(tenant_id=self.tenant_id) - assert result == {"scans_reaggregated": 2} - assert mock_agg_task.si.call_count == 2 + assert result == {"scans_reaggregated": 3} + assert mock_agg_task.si.call_count == 3 mock_agg_task.si.assert_any_call( - tenant_id=self.tenant_id, scan_id=str(scan_id_1) + tenant_id=self.tenant_id, scan_id=str(scan_id_today_p1) ) mock_agg_task.si.assert_any_call( - tenant_id=self.tenant_id, scan_id=str(scan_id_2) + tenant_id=self.tenant_id, scan_id=str(scan_id_today_p2) + ) + mock_agg_task.si.assert_any_call( + tenant_id=self.tenant_id, scan_id=str(scan_id_yesterday_p1) + ) + mock_group_result.apply_async.assert_called_once() + + @patch("tasks.tasks.group") + @patch("tasks.tasks.aggregate_finding_group_summaries_task") + @patch("tasks.tasks.Scan.objects.filter") + def test_dedupes_scans_to_latest_per_provider_per_day( + self, mock_scan_filter, mock_agg_task, mock_group + ): + """When several scans run on the same day for the same provider, only + the latest one is dispatched (matching the daily summary unique key).""" + provider_id = uuid.uuid4() + latest_scan_today = uuid.uuid4() + earlier_scan_today = uuid.uuid4() + today_late = datetime.now(tz=timezone.utc) + today_early = today_late - timedelta(hours=4) + + mock_group_result = MagicMock() + mock_group.side_effect = lambda gen: (list(gen), mock_group_result)[1] + + # Returned ordered by `-completed_at`, so the most recent comes first. + mock_scan_filter.return_value.order_by.return_value.values.return_value = [ + { + "id": latest_scan_today, + "completed_at": today_late, + "provider_id": provider_id, + }, + { + "id": earlier_scan_today, + "completed_at": today_early, + "provider_id": provider_id, + }, + ] + + result = reaggregate_all_finding_group_summaries_task(tenant_id=self.tenant_id) + + assert result == {"scans_reaggregated": 1} + mock_agg_task.si.assert_called_once_with( + tenant_id=self.tenant_id, scan_id=str(latest_scan_today) ) mock_group_result.apply_async.assert_called_once() @patch("tasks.tasks.group") @patch("tasks.tasks.Scan.objects.filter") def test_no_completed_scans_skips_dispatch(self, mock_scan_filter, mock_group): - mock_scan_filter.return_value.order_by.return_value.distinct.return_value.values_list.return_value = [] + mock_scan_filter.return_value.order_by.return_value.values.return_value = [] result = reaggregate_all_finding_group_summaries_task(tenant_id=self.tenant_id)